Skip to content

the art of the block: building an atproto tool for gut-checking your next block

There is a very specific, almost poetic flavor of digital closure that occurs when you go to block someone on social media, only to discover they already beat you to the punch. Enter bsky-mutual-blocks: a lightweight browser client designed to check your Bluesky graph, cross-reference block lists, and reveal when the antipathy across the timeline is 100% reciprocal.

taco 'bout it
Aug 28, 20263 min read

here is a very specific, almost poetic flavor of digital closure that occurs when you go to block someone on social media. No hard feelings, no lingering debates—just two people silently agreeing that neither needs to perceive the other ever again. But are you the only one that feels this way about this person you’re about to block?

Naturally, as someone who spends entirely too much time thinking about social graph mechanics (and relational data structures), I couldn’t just let that remain an occasional serendipitous discovery. I wanted to see a list of which mutual followers are blocking any given account. To solve this mystery, I decided to build a small tool.

Enter bsky-mutual-blocks: a lightweight browser client designed to check your Bluesky graph, cross-reference block lists, and reveal when the antipathy across the timeline is 100% reciprocal by showing you which of your moots are blocking someone.

the beauty of open protocols (and why this works)

On traditional siloed platforms, attempting to figure out bidirectional block states is an exercise in futility. The APIs are locked down, rate limits are punitive, and internal moderation tables are treated like state secrets.

Bluesky and the AT Protocol flip the script. Because user repositories on ATProto are publicly discoverable collections of structured records (including app.bsky.graph.block records), you don’t need privileged platform access to inspect the public topology of the network. A block on ATProto isn’t a magical black hole inside a proprietary server; it’s an explicit signed record living in a user’s public data repository.

If Alice creates a block record pointing at Bob’s DID, and Bob has a block record pointing at Alice’s DID, the overlap exists in plain daylight—you just need something to crawl the edges and do the set intersection.

Photo by Luis Gomes on Pexels

how it’s built

I wanted the tool to be fast, client-side, zero-maintenance, and entirely transparent about authentication:

Pure Browser OAuth (@atproto/oauth-client-browser)

Nobody should have to trust third-party web apps with their main credentials or app passwords just to inspect graph data. By utilizing ATProto’s browser OAuth flow with public client metadata, the user authenticates directly against their own PDS (Personal Data Server). The access token stays in the browser session, performs the lookups, and is discarded when done.

Fetching & Graph Traversal

The client fetches your active block list via the ATProto graph lexicon, paginating through blocks to resolve subject DIDs. From there, it inspects the target profiles to identify whether a reciprocal block record exists back toward your account DID.

Vite + Cloudflare Pages Deployment

The stack is minimal: TypeScript, Vite for bundling, and deployment via Cloudflare Pages (wrangler.jsonc). Fast load times, zero server infrastructure to baby, and no persistent databases caching personal graph records.

Photo by Kevin Ku on Pexels

key technical takeaways

Handling PDS Federation & Resolution: Resolving handles to DIDs and querying decentralized repositories requires graceful fallback handling for federated nodes and deleted/tombstoned accounts.

Batching & Rate Limits: Crawling hundreds of profile records sequentially in the browser will quickly trigger API throttling. Splitting queries into controlled concurrent batches keeps response times snappy without angering the endpoints.

Client-Side Privacy: By doing all comparison logic directly in the user’s browser, there’s no backend scraping, logging, or storing anyone’s block relationships.

wrap-up

Building on ATProto is a refreshing reminder of what building for the web used to feel like—open schemas, verifiable data, and the freedom to build small, fun tools just because you’re curious about network dynamics.

If you want to poke around the source or check your own mutual block count, the project repository is open source on GitHub: schwegler/bsky-mutual-blocks.

Did you enjoy this article?

Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.

Across the AtmosphereDiscussions