Delete Tweets in Bulk via API — A Developer's Tutorial
Bulk deleting your own tweets — clearing an old account before re-use, removing pre-rebrand content, post-incident cleanup — comes up in dev workflows often enough that 'delete tweets free' is a steady-traffic search. The honest answer in 2026: there is no truly free programmatic bulk-delete option that scales. X's API is consumption-based at $0.010 per delete; the third-party 'free tweet deleters' either work in small batches or operate against X's developer terms.
This guide walks the API workflow with runnable Python: fetch tweet IDs, loop deletes with rate-limit pacing, audit log per attempt. The free / cheap tier reality is at the bottom — what 'free' actually means in this space.
The straight answer — no truly free path at scale
Three options for bulk delete in 2026, ranked by cost + reliability:
1. X official API — DELETE /2/tweets/{id} at $0.010 per delete per docs.x.com pricing. Programmatic, reliable, requires OAuth user-context auth. Best for any meaningful volume.
2. Third-party 'free' deleters (TweetDeleter, TweetEraser, similar) — usually free for small batches (a few hundred tweets) then paid. Web-UI based, may use X auth on your behalf. Useful for one-off small cleanups; doesn't scale.
3. Roll-your-own via OAuth + DELETE — same X official endpoint, but you write the code. No different cost — you're paying X per delete regardless of who's calling the endpoint.
The myth of 'free bulk delete' usually points at option 2 with a hidden batch cap. The honest, scalable answer is option 1 with budget.
Step 1 — list the tweet IDs to delete
Most bulk-delete workflows have a target set: 'all tweets before 2024', 'tweets containing certain keywords', 'every tweet'. Fetch the IDs via the user timeline + filter client-side.
Via X official: /2/users/{id}/tweets with paginated cursor. Via twitterapi.io: /twitter/user/last_tweets or /twitter/tweet/advanced_search?query=from:.
import os, requests
HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"
def list_my_tweet_ids(handle: str, before_date: str = None) -> list[str]:
"""Get tweet IDs to delete via advanced_search (cheap read)."""
ids = []
cursor = None
while True:
query = f"from:{handle}"
if before_date:
query += f" until:{before_date}"
params = {"query": query}
if cursor:
params["cursor"] = cursor
r = requests.get(
f"{BASE}/twitter/tweet/advanced_search",
headers=HEADERS, params=params, timeout=15,
)
r.raise_for_status()
resp = r.json()
for t in resp.get("tweets", []):
ids.append(t["id"])
cursor = resp.get("next_cursor")
if not cursor: break
return ids
old_tweets = list_my_tweet_ids("your_handle", before_date="2024-01-01")
print(f"found {len(old_tweets)} tweets to delete")
# Cost: ~$0.00015 × len(old_tweets) — read is cheap; delete is the bill
Step 2 — execute the deletes with rate-limit safety
Once you have the ID list, loop the DELETE calls. X publishes rate limits; pacing 1-2 seconds between deletes is the operational baseline.
Per docs.x.com/x-api/getting-started/pricing: $0.010 per delete. 1,000-tweet cleanup = $10. 10,000-tweet cleanup = $100.
# pip install tweepy
import tweepy, time, json, random
from datetime import datetime, timezone
client = tweepy.Client(
consumer_key="YOUR_KEY",
consumer_secret="YOUR_SECRET",
access_token="USER_TOKEN",
access_token_secret="USER_TOKEN_SECRET",
)
def bulk_delete(tweet_ids: list[str], dry_run: bool = True):
"""Delete tweets with audit log + rate-limit safety."""
log_path = f"delete_log_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}.jsonl"
success, fail = 0, 0
with open(log_path, "a") as log:
for tid in tweet_ids:
entry = {"tweet_id": tid, "at": datetime.now(timezone.utc).isoformat()}
if dry_run:
entry["action"] = "dry_run"
log.write(json.dumps(entry) + "\n")
continue
try:
client.delete_tweet(id=tid)
entry["action"] = "deleted"
success += 1
except tweepy.TooManyRequests:
entry["action"] = "rate_limited"
log.write(json.dumps(entry) + "\n")
time.sleep(60 + random.uniform(0, 5))
continue
except Exception as e:
entry["action"] = f"failed: {e}"
fail += 1
log.write(json.dumps(entry) + "\n")
time.sleep(1.0 + random.uniform(0.1, 0.5)) # safe pacing
return {"success": success, "fail": fail, "log": log_path}
# Always run dry_run=True first to verify the target set
# result = bulk_delete(old_tweets, dry_run=False)
Free / cheap alternatives — what 'free' actually means
Third-party tools advertised as 'free tweet deleter':
- TweetDeleter, TweetEraser, Circleboom, Redact (formerly TweetDelete) — web UIs that bulk-delete via the user's X auth. Free tier typically caps at a small monthly batch (e.g. 3,000 tweets/mo); past that, paid plans apply.
- Browser extensions — DIY scripts that programmatically scroll your timeline and click delete in the UI. Slow + fragile (UI changes break them). Some violate X's terms of service depending on implementation.
- 'Permanent free' deleters — usually have hidden batch caps or sustainable-volume limits. Try one for a small test before relying on it for a 10K cleanup.
The honest tradeoff: free options work for small one-time cleanups (< 1,000 tweets); paid / API options are the path for any meaningful scale or recurring workflow.
Side-by-side comparison — 3 paths to bulk delete
Two practical patterns: (a) the API path is the only programmatic + reliable path at scale; (b) free options are good for one-off small jobs, not for recurring workflows.
Cost framing + scaling
Math from docs.x.com pricing at $0.010 per delete:
- 100 tweet cleanup = $1.00
- 1,000 tweet cleanup = $10.00
- 10,000 tweet cleanup = $100.00
Plus the cost of listing target IDs — at twitterapi.io's $0.00015/tweet read, that's negligible (1,000 IDs to read = $0.15).
Rate-limit pacing means a 10K-tweet cleanup takes ~6 hours of wall-clock at 1.5 sec/delete. Plan accordingly.
# Practical example: end-to-end old-tweet cleanup with dry-run + audit log.
import os, time, random, json
import tweepy, requests
from datetime import datetime, timezone
TAPI_HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
client = tweepy.Client(
consumer_key=os.environ["X_CONSUMER_KEY"],
consumer_secret=os.environ["X_CONSUMER_SECRET"],
access_token=os.environ["X_USER_TOKEN"],
access_token_secret=os.environ["X_USER_SECRET"],
)
HANDLE = os.environ["X_HANDLE"]
DRY_RUN = True # always start safe
def list_targets(before_date: str):
ids = []
cursor = None
while True:
params = {"query": f"from:{HANDLE} until:{before_date}"}
if cursor: params["cursor"] = cursor
r = requests.get(
"https://api.twitterapi.io/twitter/tweet/advanced_search",
headers=TAPI_HEADERS, params=params, timeout=15,
)
r.raise_for_status()
resp = r.json()
for t in resp.get("tweets", []):
ids.append(t["id"])
cursor = resp.get("next_cursor")
if not cursor: break
return ids
def bulk_delete(ids):
log_path = f"delete_log_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}.jsonl"
success, fail = 0, 0
with open(log_path, "a") as log:
for tid in ids:
entry = {"tweet_id": tid, "at": datetime.now(timezone.utc).isoformat()}
if DRY_RUN:
entry["action"] = "dry_run"
else:
try:
client.delete_tweet(id=tid)
entry["action"] = "deleted"
success += 1
except tweepy.TooManyRequests:
entry["action"] = "rate_limited"
log.write(json.dumps(entry) + "\n")
time.sleep(60 + random.uniform(0, 5))
continue
except Exception as e:
entry["action"] = f"failed: {e}"
fail += 1
log.write(json.dumps(entry) + "\n")
time.sleep(1.0 + random.uniform(0.1, 0.5))
return success, fail, log_path
targets = list_targets("2024-01-01")
print(f"found {len(targets)} tweets to delete")
print(f"Estimated cost (X official): ${len(targets) * 0.010:.2f}")
print(f"Time at 1.5s pace: ~{len(targets) * 1.5 / 60:.0f} minutes")
if not DRY_RUN:
s, f, p = bulk_delete(targets)
print(f"Done: {s} deleted, {f} failed. Log: {p}")
Questions readers ask
Is there really no free bulk-delete API in 2026?
Not at scale. X's API is consumption-based with no free tier in 2026. Third-party 'free' tools work for small one-off cleanups (under 1,000 tweets typically) but don't scale to recurring or large workflows. The honest tradeoff: pay for the API or accept the batch caps.
Can I undo a bulk delete?
No — tweet deletes are permanent. There is no undelete API. Run dry_run=True first to verify your target set, and consider exporting the tweets you're about to delete first (see /blog/twitter-history-api-export-guide for the export workflow).
Will X suspend my account for bulk deleting?
Bulk-deleting your own tweets via the API is a standard supported workflow — not against X's terms. The risk is rate-limit violations if you go too fast. Pace 1-2 seconds between deletes; don't burst.
Can I delete other users' tweets?
No — you can only delete your own tweets. OAuth user-context auth scopes the call to the authenticated account. Reporting other users' content is a separate moderation workflow, not the delete API.
What about archiving before delete?
Strongly recommended for any meaningful cleanup. Export the tweets first via twitterapi.io advanced_search to JSONL (single-digit-dollar cost), then run the deletion. Archive lives outside X regardless of what happens to your account.
How long does a 10K-tweet bulk delete take?
At 1.5 second pacing per delete: 10,000 × 1.5s = 15,000 seconds = ~4.2 hours of wall-clock time. Plus any rate-limit pauses. Run overnight, monitor for completion.
Continue
- X API — pricing (docs.x.com, 2026 verified)
- Tweepy documentation
- twitterapi.io — pricing (read-only API)
- Twitter (X) API — cluster hub
- Mass unfollow Twitter (X) API tutorial
- Twitter (X) history API — export timeline
- Rate Limit Exceeded on Twitter (X) — Fixes
- twitterapi.io pricing
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API key