Bulk-delete your own X.com (Twitter) likes and replies, from your browser, with a click.
Batchd is a small Tampermonkey userscript
that walks your Likes tab (/likes) and your Replies tab
(/with_replies) on x.com and removes the engagement, one post at a time,
with careful pacing so X's anti-abuse systems stay quiet. No API token,
no account credentials, no upload of your data anywhere β the script runs
entirely in your already-logged-in browser.
If you want to clean up years of "hearted" posts, or wipe the replies you regretted, Batchd is the tool.
- Why this tool
- Features
- Quick start
- Safety
- Browser compatibility
- How it works
- Compare to alternatives
- Limitations
- Development
- License
Most "bulk delete" tools for X are paid SaaS dashboards that ask for your account credentials or an OAuth token and then act on your behalf from a server. That has three problems:
- You have to trust a third party with full account access.
- Your data passes through someone else's server.
- They cost money.
Batchd is the alternative: a single JavaScript file you install in Tampermonkey that runs in the browser tab you're already logged in to. It reads post IDs from the rendered timeline and clicks the existing on-screen controls. Your session cookie is reused, your data never leaves your machine, and there's nothing to pay for.
- π Bulk unlike X.com posts β walks
/likesand unlikes each visible post - ποΈ Bulk delete X.com replies β walks
/with_repliesand drives the more-menu β Delete β confirm sequence - π No API token, no OAuth, no credentials β uses your existing browser session
- π‘οΈ No data leaves your machine β no server, no upload, no telemetry
- π Open source (MIT) β read the code, fork it, run it on your own data without trusting anyone
- β±οΈ Pacing controls β adjustable base delay, jitter, batch pause, and exponential backoff to stay under X's anti-abuse radar
- π§ͺ Dry-run mode β walks the timeline and logs what it would click without actually clicking, so you can verify it sees the right posts
- π Resumable β the script remembers which posts it has already processed and skips them on subsequent runs
- βοΈ Per-category pacing β likes are faster (1200ms base) because unliking is cheap; replies are slower (3000ms base) because delete is destructive and X treats it more strictly
- β²οΈ Stopwatch β see how long the run has been going
- βΉοΈ Stop button β abort mid-run without losing progress
- π§ One-click navigation β
β /likesandβ /with_replieslinks in the panel take you to the right tab automatically
Pick whichever install path matches your browser:
Option A β π Chrome Web Store extension (v0.3.1+, recommended on Chrome):
- Open the Batchd Chrome Web Store listing and click Add to Chrome. (Link goes live once the v0.3.0 submission is approved by the Chrome Web Store review team.)
- Go to x.com in a regular tab (logged in to the account whose likes/replies you want to delete).
- A small panel appears in the bottom-right corner of every x.com page.
Tick the mode you want (Likes is on by default), navigate to the
right tab via the
β /likesorβ /with_replieslink, typeDELETEto confirm, and click Go.
Option B β π΅ Tampermonkey (Firefox, Safari, Edge, or any other browser):
- Install Tampermonkey in your browser: Chrome, Firefox, Edge, or any other browser that supports userscripts. (Violentmonkey also works.)
- Install the script: open
dist/batchd.user.jsfrom this repo, or drag-and-drop it into a browser tab. Tampermonkey will prompt to install. Approve. - Go to x.com (same logged-in-account requirement as Option A).
- Same panel appears; same
DELETEβ Go flow.
That is the whole flow. The script will scroll the timeline, unlike/delete each visible post one at a time, and stop when the timeline is exhausted (or when you hit Stop).
β οΈ This script permanently deletes engagement from your X.com account. There is no undo.
- Likes are recoverable (you can re-like a post later if you find it in your history, though the script does not track which posts it unliked).
- Replies are not recoverable. Once a reply is deleted, the text and the thread context are gone for everyone who saw them.
Before a real run:
- Run in dry-run mode first (tick the Dry run checkbox). The script will walk the timeline and log every post it would click, without actually clicking. Verify the panel log shows the kind of posts you expect.
- Try a small slice before committing to a multi-hour run. Untick Dry run, leave the panel running for a few minutes, and watch the stats to make sure the success counter is going up.
- The Go button requires you to type
DELETEbefore it will start. This is the only guardrail. If a young child or a curious cat has access to your browser, lock the panel behind your OS screen lock.
The script also does not handle the case where someone is logged in to multiple X accounts in the same browser β it operates on whichever account is currently signed in.
| Browser | Works? |
|---|---|
| Chrome (extension β v0.3.1+) | β β preferred Chrome install path |
| Chrome (Tampermonkey) | β |
| Firefox (Tampermonkey or Violentmonkey) | β |
| Edge (Tampermonkey) | β |
| Safari (Tampermonkey) | β |
| Opera (Tampermonkey) | β |
| Brave (Tampermonkey) | β |
| Mobile browsers | β β needs a desktop userscript manager or Chrome desktop |
Batchd ships as two install paths β a Tampermonkey userscript and a
Chrome MV3 extension β both built from a single src/ tree of ESM
modules concatenated by scripts/build.js. The userscript bundle
(dist/batchd.user.js) is around 78KB; the Chrome bundle
(dist/extension/) is similar.
The architecture is intentionally minimal:
Show module-by-module breakdown
Shared logic modules (used by both install paths):
src/selectors.jsβ the only module that touches the X.com DOM. Three-signal fallback chains (X rotates testid attributes between front-end releases) for the unlike control, the more-menu trigger, the menu item, and the delete-confirm button. This is the file you patch if X changes a selector β one function per concern.src/run.jsβ the run loop. Identical structure for both Likes and Replies: refill loop, idle watchdog, batch pause, failure backoff. The only per-category inputs are the click action and the pacing preset.src/persist.jsβ state. Per-category stats (likes/replies), per-category cursors, shared processed set, two pacing presets. Includes migrations from the v0.1.0 state shape.src/failures.jsβ outcome classifier. Maps click results to one of eight kinds:success,already_gone,not_actionable,network,rate_limited,captcha,unknown,stale.src/pacing.jsβ pure functions for delay, batch pause, and exponential backoff.src/yield.jsβ coexistence guard. If a user has both the Tampermonkey userscript and the Chrome extension installed, the first to mount claimswindow.__batchdand the second bails with a one-time console message.src/entry.jsβ the shared bootstrap.bootstrapBatchd()wires the modules together so the chrome and tampermonkey entry points stay thin.src/safeCall.jsβ small helper for swallowing exceptions from optional DOM/storage calls.src/panel.jsβ the floating bottom-right control panel.
Storage adapters (one per install path):
src/storage.gm.jsβ wrapsGM_getValue/GM_setValuefor Tampermonkey. Returns aget/setfactory consumed bysrc/batchd.user.js.src/storage.chrome.jsβ wrapschrome.storage.localfor the Chrome extension. Returns the same shape. Falls back gracefully when the chrome runtime reportslastError.
Entry points:
src/batchd.user.jsβ the Tampermonkey entry. Wires the storage.gm.js adapter, callsbootstrapBatchd().src/content.jsβ the Chrome extension entry. Wires the storage.chrome.js adapter, calls the samebootstrapBatchd().
The full v0.3.0 architecture (why one src/ tree with two build
targets) is captured in
ADR 0004.
For a glossary of terms used throughout the codebase, see
CONTEXT.md.
No network calls of any kind. The only cookies used are the ones your browser already has for x.com.
There are several other tools for cleaning up your X.com history. Here is how Batchd compares:
Show full comparison table
| Tool | What it does | Account access | Open source | Cost | X.com likes | X.com replies |
|---|---|---|---|---|---|---|
| Batchd (this project) | Bulk unlike + bulk delete replies | Uses your browser session, no credentials shared | β MIT | Free | β | β |
| Semiphemeral | Auto-archive old tweets after N days | OAuth | β | Paid | β (archives only) | β |
| Redact | Bulk delete tweets, retweets, likes | OAuth | β | Paid | β | β |
| TweetDelete | Bulk delete with date/keyword filters | OAuth | β | Paid (free tier limited) | β | β |
| TweetEraser | Bulk delete + unlike | OAuth | β | Paid | β | β |
| Semiphemeral-likes | Various open-source forks, mostly unmaintained | Varies | β | Free | β | β |
| X.com native "archive / delete" UI | One at a time, in the browser | N/A (manual) | N/A | Free | β (no bulk) | β (one at a time) |
Why Batchd is different:
- π No credentials, no server. Nothing leaves your machine. The paid SaaS tools all require you to grant OAuth access, which means your tweets, DMs, and account metadata are processed on their servers (read their privacy policies).
- ποΈ Open source. You can read the full code, audit it, fork it, modify it for your own needs, and contribute back.
- π¬β€οΈ Likes and replies. Most tools only handle one. Batchd handles both, with a different pacing profile per category because deleting a reply is more sensitive than unliking a post.
- πΎ Resumable. If you close the tab or hit Stop, the script remembers which posts it has already processed and resumes from the saved cursor on the next run.
- π Open and free, forever. No free tier that suddenly becomes paid, no acquisition risk, no shutdown risk.
- Reposts and quote reposts are not supported. X's "Undo repost" UI is unreliable and the prior Batchd implementation that handled them was removed. Restoring that flow needs a new design pass.
- Non-reply tweets are not supported. The "Tweets" tab of your profile is not bulk-deletable from this script β only the "Replies" tab is. (You can still delete individual tweets via X's native UI.)
- DMs and bookmarks are not touched.
- One account at a time. The script operates on whichever X.com account is currently logged in to your browser.
- Pacing is not magic. X's anti-abuse systems are a moving target. If you run too aggressively (low delay, no batch pause), the script may hit rate limits or captcha. The defaults are conservative; if you see captcha, stop, wait, and run again with default pacing.
git clone https://github.com/11sid11/Batchd.git
cd Batchd
npm install
npm test # runs the unit test suite (120 tests)
npm run build # builds both artifacts: userscript + extension
npm run build:userscript # dist/batchd.user.js only
npm run build:extension # dist/extension/ only (manifest + content.js + icons/)
npm run icons # regenerates extension/icons/*.png from assets/logo.svgThe build output for Tampermonkey is dist/batchd.user.js; for the
Chrome extension it's dist/extension/. Both are emitted from the same
src/ tree. The src/ files are ESM modules and not directly runnable.
Tests use node --test against the source modules with mocked DOM
(src/selectors.js is the main DOM-touching file; the others are pure
logic). 120 test cases cover pacing, persistence, the run loop, the
storage adapters, the yield guard, selector behavior, and the two
build-script bundle smoke tests (chrome extension + TM userscript).
This is a personal-use tool. Contributions are welcome β open an issue first if you want to discuss a change larger than a small fix.
If Batchd saved you time, a tip is appreciated β never required.
- β Buy Me A Chai β INR, UPI, cards, netbanking
- π Solana β
7fK5mh8RXhop4sojEQL2UqNkgRWqDEindTBj6KWRjhGM(Solscan)
The support links also live inside the floating panel (footer of the Batchd overlay on x.com) so they're discoverable while the script is running.
MIT. Use it, fork it, ship it. Attribution appreciated but not required.
