{"id":22942049,"url":"https://github.com/async3619/cage","last_synced_at":"2025-09-13T15:41:39.957Z","repository":{"id":64322954,"uuid":"571823918","full_name":"async3619/cage","owner":"async3619","description":"(almost) realtime unfollower detection for any social services 🦜⛓️🔒","archived":false,"fork":false,"pushed_at":"2024-11-01T06:38:01.000Z","size":698,"stargazers_count":28,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"dev","last_synced_at":"2025-08-28T17:56:05.859Z","etag":null,"topics":["cli","followers","github","instagram","nodejs","sns","social","tiktok","twitter","youtube"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/async3619.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-29T00:42:22.000Z","updated_at":"2025-08-22T00:50:02.000Z","dependencies_parsed_at":"2024-10-31T17:24:16.403Z","dependency_job_id":"dd59d0fd-12f9-4a31-a8fe-642eaefe8098","html_url":"https://github.com/async3619/cage","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/async3619/cage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async3619%2Fcage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async3619%2Fcage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async3619%2Fcage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async3619%2Fcage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/async3619","download_url":"https://codeload.github.com/async3619/cage/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async3619%2Fcage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274985731,"owners_count":25385961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-13T02:00:10.085Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","followers","github","instagram","nodejs","sns","social","tiktok","twitter","youtube"],"created_at":"2024-12-14T13:46:26.470Z","updated_at":"2025-09-13T15:41:39.914Z","avatar_url":"https://github.com/async3619.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003e\n  \u003cbr /\u003e\n  🦜\n  \u003cbr /\u003e\n  Cage\n  \u003csup\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n  \u003c/sup\u003e    \n\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://registry.hub.docker.com/r/async3619/cage\"\u003e\n        \u003cimg alt=\"Docker Image Version (latest by date)\" src=\"https://img.shields.io/docker/v/async3619/cage?label=docker\u0026style=flat-square\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/cage-cli\"\u003e\n        \u003cimg alt=\"npm (tag)\" src=\"https://img.shields.io/npm/v/cage-cli/dev?style=flat-square\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/async3619/solv/blob/main/LICENSE\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/license/async3619/solv.svg?style=flat-square\" alt=\"MIT License\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://app.codecov.io/gh/async3619/cage\"\u003e\n        \u003cimg alt=\"Codecov\" src=\"https://img.shields.io/codecov/c/github/async3619/cage?style=flat-square\u0026token=97JBTXGXC8\"\u003e\n    \u003c/a\u003e\n    \u003cbr /\u003e\n    \u003csup\u003e(almost) realtime unfollower detection for any social services\u003c/sup\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n\u003c/div\u003e\n\n## Introduction\n\nCage is a cli application for detecting unfollowers on any social services. this application will check all of your followers using each watcher and compare them to the previous check. if there is a difference, it will notify you of the changes.\n\n## Usage\n\n```bash\n$ npm install -g cage-cli@dev\n\n$ cage --help\n\nUsage: cage [options]\n\n(almost) realtime unfollower detection for any social services 🦜⛓️🔒\n\nOptions:\n  -c, --config \u003cpath\u003e    path to the configuration file (default: \"./config.json\")\n  -d, --database \u003cpath\u003e  path to the database file (default: \"./data.sqlite\")\n  -p, --drop-database    delete the old database file\n  -v, --verbose          enable verbose level logging\n  -V, --version          output the version number\n  -h, --help             display help for command\n```\n\nor you can just deploy with `docker` if you want:\n\n```bash\n$ docker run -d --name cage async3619/cage -v /path/to/config.json:/home/node/config.json\n```\n\nof course, you can also use `docker-compose`:\n\n```yaml\nversion: \"3.9\"\n\nservices:\n    cage:\n        image: async3619/cage\n        volumes:\n            - /path/to/config.json:/home/node/config.json\n```\n\n## Watchers and Notifiers\n\n### Watchers\n\n`Watchers` are independent feature that has the ability to watch to check users who follow your account per service.\n\n#### Supported Watchers\n\n| Service   | Support? |\n|-----------|:--------:|\n| Twitter   |    ✅     |\n| GitHub    |    ✅     |\n| Mastodon  |    ✅     |\n| Instagram |    ✅     |\n| TikTok    |    ❌     |\n| YouTube   |    ❌     |\n| Twitch    |    ❌     |\n| Facebook  |    ❌     |\n| Reddit    |    ❌     |\n| Discord   |    ❌     |\n\n### Notifiers\n\nWhen we detect unfollowers, new followers, or any other events, Cage will notify you via `Notifiers`.\n\n#### Supported Notifiers\n\n| Service         | Support? |\n|-----------------|:--------:|\n| Discord Webhook |    ✅     |\n| Telegram Bot    |    ✅     |\n| Slack Webhook   |    ✅     |\n| Email           |    ❌     |\n| SMS             |    ❌     |\n\n## Configuration\n\nthis application reads configuration file from `./cage.config.json` by default.\nif there's no configuration file to read, this application will create you a default configuration file for you:\n\n```json\n{\n    \"watchInterval\": 60000,\n    \"watchers\": {},\n    \"notifiers\": {}\n}\n```\n\nyou can use json schema file `config.schema.json` on this repository.\n\n### watchInterval: `number` (required)\n\nspecify watching interval in millisecond format. minimal value is `60000`.\n\n### watchers: `Record\u003cstring, WatcherOptions\u003e` (required)\n\n#### twitter\n\nInternally, Cage uses [Rettiwt-API](https://github.com/Rishikant181/Rettiwt-API) to get the followers list. so you need to get the API Key with extensions that provided by the author. you can see the instruction [here](https://github.com/Rishikant181/Rettiwt-API#1-using-a-browser-recommended).\n\n```json5\n{\n    \"type\": \"twitter\", // required\n    \"apiKey\": \"API Key that retrieved with X Auth Helper extension\", // string, required\n    \"username\": \"your twitter username\", // string\n}\n```\n\n#### github\n\nwatcher configuration for GitHub service.\n\n```json5\n{\n    \"type\": \"github\", // required\n    \"authToken\": \"personal access token of your github account\" // string, required\n}\n```\n\n#### instagram\n\nwatcher configuration for Instagram service.\n\n```json5\n{\n    \"type\": \"instagram\", // required\n    \"username\": \"your instagram username\", // string, required\n    \"password\": \"your instagram password\", // string, required\n    \"targetUserName\": \"target instagram username you want to crawl followers\", // string, required\n    \"requestDelay\": 1000 // number, optional, default: 1000\n    // requestDelay is the delay time between each request to instagram server.\n    // this is to prevent getting banned from instagram server.\n}\n```\n\n### notifiers: `Record\u003cstring, NotifierOptions\u003e` (required)\n\n#### discord\n\nnotifier configuration for Discord Webhook notifier.\n\n```json5\n{\n    \"type\": \"discord\",\n    \"webhookUrl\": \"Discord Webhook url\" // string, required\n}\n```\n\n#### telegram\n\nnotifier configuration for Telegram Bot notifier.\n\n```json5\n{\n    \"type\": \"telegram\",\n    \"botToken\": \"token that generated from https://t.me/CageNotifierBot\", // string, required\n    \"url\": \"custom notification relay server url\" // string, optional\n}\n```\n\nIn most cases, you will not need `url` property since since Cage already provides hosted version of this server out of the box. but if you want to use custom notification relay server, take a look [this repoitory](https://github.com/async3619/cage-telegram-helper#usage).\n\n#### slack\n\nnotifier configuration for Slack Webhook notifier.\n\n```json5\n{\n    \"type\": \"slack\",\n    \"webhookUrl\": \"Slack Webhook url\" // string, required\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasync3619%2Fcage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasync3619%2Fcage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasync3619%2Fcage/lists"}