garden / projects / bsky-mutual-blocks
AT Protocol · Social Graph Auditing · Edge Hosted

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.

Stack: React 18 TypeScript Vite Tailwind CSS @atproto/api Cloudflare Pages 100% Client-Side

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:

1. Auth / Handle Resolve DID & initialize session
2. Graph Fetch Paginate follows & followers
3. Set Intersection Filter mutual DIDs
4. Batch Audit Query block records & states
5. Report Render Display table, stats & export

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 list
  • app.bsky.graph.getFollowers — Cursor-based followers list
  • app.bsky.graph.getRelationships — Batch relationship status query
  • app.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 main branch
  • Global Anycast Edge CDN distribution with minimal TTFB
  • Zero server management or runtime infrastructure costs
src/utils/mutualsScanner.ts
TypeScript / @atproto/api
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;
}

Explore the Project

Check out the live web tool or inspect the complete TypeScript source repository.