Bluesky Mutuals
Block Checker
A secure, client-side analysis tool built on the AT Protocol to scan mutual follow connections, audit asymmetrical block relationships, and detect top blockers across decentralized social graphs.
Project Overview & Purpose
The Problem Space
In decentralized social networks using the AT Protocol (such as Bluesky), social graph operations like follows, mutes, and blocks are stored as individual records in distributed user repositories (PDS). Because timelines and feeds can suppress blocked posts silently or produce disjointed reply trees, users frequently experience unexplained interaction drops among their mutual connections.
The Solution
Bluesky Mutuals Block Checker provides a transparent, zero-install web interface that authenticates directly with Bluesky, computes the exact intersection of your follow graph (A ∩ B), and audits block statuses and top blockers within your mutual circle in real time.
Key Features
Mutual Follows Isolation
Fetches full follows and follower collections via cursor pagination and calculates bidirectional mutuals.
Block Relationship Audit
Queries AT Protocol relationship endpoints to isolate incoming blocks, outgoing blocks, and reciprocal block states.
Top Mutual Blockers Scan
Aggregates network block telemetry to identify third-party accounts that hold the highest number of blocks among your mutuals.
Privacy & Zero Retention
Operates 100% in the client's browser. No database, no backend server logging credentials, and no external tracking.
Intelligent Throttling
Batched XRPC requests with dynamic concurrency limits and exponential backoff to respect Bluesky rate limits.
Data Exporting
Quickly export full audit findings and account DID manifests to CSV or JSON formats for offline review.
Architecture & Data Flow
Because the application is hosted statically on Cloudflare Pages, communication occurs directly between the browser runtime and Bluesky's AppView/PDS infrastructure via XRPC calls:
Technical Deep Dive & Code Architecture
AT Protocol Lexicon APIs
Core Engine
Uses @atproto/api to interface with XRPC endpoints. Key lexicons utilized:
app.bsky.graph.getFollows— Cursor-based following listapp.bsky.graph.getFollowers— Cursor-based followers listapp.bsky.graph.getRelationships— Batch relationship status queryapp.bsky.actor.getProfile— Hydrating handle, display name & avatar
Cloudflare Pages & CI/CD
Edge Infra
Continuous deployment hooked directly into GitHub (schwegler/bsky-mutual-blocks).
- Automatic branch previews on pull requests
- Production deploys directly from
mainbranch - Global Anycast Edge CDN distribution with minimal TTFB
- Zero server management or runtime infrastructure costs
import { BskyAgent } from '@atproto/api'; // 1. Compute Mutual Accounts from Follow & Follower collections export async function getMutuals(agent: BskyAgent, actorDid: string) { const follows = await fetchAllFollows(agent, actorDid); const followers = await fetchAllFollowers(agent, actorDid); const followerDidSet = new Set(followers.map(f => f.did)); return follows.filter(f => followerDidSet.has(f.did)); } // 2. Batch-Query Relationship Statuses to detect block flags export async function auditRelationships(agent: BskyAgent, mutualDids: string[]) { const BATCH_SIZE = 30; const results = []; for (let i = 0; i < mutualDids.length; i += BATCH_SIZE) { const batch = mutualDids.slice(i, i + BATCH_SIZE); const res = await agent.app.bsky.graph.getRelationships({ actor: agent.session?.did!, others: batch }); results.push(...res.data.relationships); } return results; }