A CLI utility to clean up inactive or undesirable X/Twitter accounts you follow.
Pure Node.js (>= 20), zero runtime dependencies, no build step.
There is no free X API tier. The API is pay-per-usage (credits bought in the Developer Console). cleanx is designed to be as cheap as possible: scanning costs ~$0.001 per followed account (Owned Reads pricing), each unfollow ~$0.010, each re-follow ~$0.015. Every paid operation prints a cost estimate and asks before spending, writes are dry-run unless you pass
--execute, and everything fetched is cached locally so you never pay twice for the same data (X deduplicates resource charges within a 24h window).
cleanx auth setup → store your app credentials
cleanx following scan → fetch + cache the accounts you follow (paid, ~$0.001/account)
cleanx following report → review flagged accounts from the cache (free)
cleanx following clean → interactive checklist → saves a plan (free, dry-run)
cleanx following clean --execute → paced unfollows from the plan (paid, ~$0.010/unfollow)
cleanx following restore → re-follow from the undo journal if needed (paid, ~$0.015/follow)
Inactivity is detected without extra API calls: each user object carries
most_recent_tweet_id, and tweet IDs are snowflakes — the timestamp is decoded
client-side ((id >> 22) + 1288834974657ms).
Flags reported per account: inactive (default: no post in 180+ days), never-tweeted,
suspended, no-bio, low-followers, not-mutual, default-avatar, protected.
- Create an X developer app at console.x.com and buy some credits (a few dollars is plenty).
- In the app's User authentication settings, set permissions to Read and write.
The form also requires a Callback URI and Website URL — cleanx uses OAuth 1.0a
with console-generated tokens, so no redirect flow ever happens; placeholders like
http://localhost/and your profile URL are fine. - Then generate your Access Token & Secret (tokens inherit the permissions at generation time — if you set permissions after, regenerate them).
- Run
cleanx auth setupand paste the four values from the Keys and tokens page. The prompts use the console's exact labels: API Key and API Secret (listed under "Consumer Keys") identify the app; Access Token and Access Token Secret represent your account. Credentials are stored in~/.config/cleanx/config.jsonwith mode600. (Env varsX_API_KEY,X_API_SECRET,X_ACCESS_TOKEN,X_ACCESS_SECRETalso work.)
Owned Read pricing ($0.001/user instead of $0.010) requires the authenticated user to be the owner of the developer app — which is exactly this setup.
node bin/cleanx.js --help # run in place
npm link # optional: puts `cleanx` on your PATH
npm test # run the test suiteStore credentials, verify them against GET /2/users/me, and show your locally
estimated spend. (status makes one ~$0.01 API call.)
Estimates cost from your following_count, asks, then pages through
GET /2/users/:id/following (1000/page) and caches everything under
~/.local/share/cleanx/. Suspended accounts are captured as tombstones.
Each scan also writes a timestamped following.export-* copy.
cleanx following report [--format table|json|csv] [--out file] [--sort key] [--inactive-days n] — free
Renders the cache with flags. No credentials or API calls needed.
Builds candidates, opens an interactive checklist (all pre-checked — uncheck the accounts you want to keep), and saves a plan file. Nothing is unfollowed.
Rules (OR'ed): --inactive-days n, --never-tweeted, --suspended, --no-bio,
--not-mutual, --max-followers n. With no rule flags, the default set is
inactive + never-tweeted + suspended. --keep-file f protects usernames/IDs
(one per line).
Runs the saved plan: DELETE /2/users/:id/following/:target paced at ~18s per
request (respecting the 50/15min API limit), daily cap 200, automatic
x-rate-limit-reset waits, resumable after interruption. Every action is appended
to a JSONL journal (~/.local/share/cleanx/journal/) for undo.
Interactive checklist of previously unfollowed accounts to re-follow.
Manage local documents. clear keeps the journal unless --include-journal is given.
- X enforces anti-churn limits beyond the API rate limits. The default pacing (18s, 200/day) is conservative; lowering the cap is fine, raising it is your risk.
- Unfollows are journaled and reversible via
restore. Nothing else is written to your account by this tool. - Not affiliated with X. Use at your own risk; prices may change — the ledger is an estimate, the Developer Console is the source of truth.
The architecture is domain-oriented (following is the first domain). Planned:
cleanx tweets scan|report|clean (delete old posts — same scan→flag→review→paced-delete
pipeline, journaled as an archive since deletion is irreversible), cleanx likes clean.