For anyone running their own PDS
Delete posts and likes on a self-hosted PDS
Deletem is not tied to bsky.social. Sign in with your handle and it resolves your PDS from your DID, then talks to that server for the whole session. Both did:plc and did:web identities work.
How signing in finds your PDS
You type a handle. Deletem resolves it to a DID, reads that DID document to find the PDS endpoint it names, then discovers that server's OAuth authorization server and sends you there to approve access. You authenticate against your own PDS — your password is never typed into Deletem, and Deletem never receives it.
For did:web, the DID document is fetched from the domain in the DID. For did:plc, it comes from the PLC directory. Either way the PDS endpoint is validated before any request is made to it — a DID document is attacker-controlled input, so endpoints resolving to loopback, link-local or private address ranges are rejected rather than fetched.
What Deletem deletes
Three collections, and nothing else. Deletem is host-agnostic but not lexicon-agnostic — it understands Bluesky records specifically.
app.bsky.feed.postPosts, replies and quote postsapp.bsky.feed.likeLikesapp.bsky.feed.repostReposts
What it leaves alone
Everything else in your repo survives a delete run, including records from other atproto apps. If you run a PDS with a blogging or link-aggregator app alongside Bluesky, Deletem will not touch that data — it also will not help you clean it up.
app.bsky.graph.followFollowsapp.bsky.graph.blockBlocksapp.bsky.graph.list, listitemLists and their membersapp.bsky.actor.profileYour profile recordapp.bsky.feed.threadgate, postgateReply and quote controlsEverything elseRecords written by any other atproto app
What works, and what degrades
Listing and deleting are pure AT Protocol. Records are read with com.atproto.repo.listRecords and removed with com.atproto.repo.deleteRecord, both against your own PDS. Likes are read from a com.atproto.sync.getRepo CAR export where available, falling back to paginated listing. None of that involves Bluesky infrastructure.
Engagement counts are the exception. Like and repost totals shown on each post come from the Bluesky AppView, so if your PDS does not federate with it those numbers may be missing or stale. Filtering, previewing and deleting still work — you just lose the counts, not the function.
Permissions it asks for
Deletem requests granular scopes matching exactly what it calls. Notably the write scope is delete-only: there is no permission to create or edit records, so it cannot post as you.
repo:*?action=deleteDelete records from your repo. Delete only — no create, no update.rpc:com.atproto.repo.listRecordsList your posts, likes and reposts so they can be shown and filtered.rpc:com.atproto.repo.getRecordRead an individual record when the list view needs its contents.rpc:com.atproto.repo.deleteRecordPerform the deletion itself.rpc:com.atproto.repo.describeRepoResolve your handle from your DID.rpc:app.bsky.feed.getAuthorFeedFallback listing path, and the source of engagement counts.rpc:app.bsky.feed.getPostsFill in like and repost counts on posts already listed.
Rate limits on your own server
Deletem paces deletions against Bluesky's published limits — roughly 5,000 per hour and 35,000 per day — pausing and resuming automatically when it approaches them.
On your own PDS the real limits are whatever you configured, which may be higher or lower. Deletem does not currently read them from the server, so it applies the same pacing regardless. If your limits are tighter you may still see rejections; if they are looser, runs will finish more slowly than your server strictly requires.
Ready to try it?
Sign in with your handle. Preview mode runs a full dry-run first, so you can see exactly what matches before anything is removed.
Get started