31 views 17 mins 0 comments

Your App Can Join the Fediverse: A Practical ActivityPub Playbook

In Featured, Guides, It's happening, Technology
November 12, 2025
Your App Can Join the Fediverse: A Practical ActivityPub Playbook

Why Your App Should Federate Now

The social web is becoming a network of networks. Blogs, forums, photo apps, and big platforms are adding federation so users can follow, reply, and share across different services. The protocol behind much of this is ActivityPub, a W3C standard that defines how servers exchange social activities over HTTPS using JSON.

If you run a community app or publish user content, federation gives you reach, portability, and resilience. Your users can interact with people on other servers without creating new accounts, and you retain control over your product and policies. This article is a practical playbook: what to build, how to handle safety and scale, and how to ship without getting lost in the standards.

What ActivityPub Actually Gives You

At its core, ActivityPub defines actors (people, groups, apps), objects (posts, images, links), and activities (create, follow, like). It uses the ActivityStreams 2.0 vocabulary and JSON-LD formatting. There are two main flows:

  • Server-to-server: delivery of activities between domains (what you’ll implement first).
  • Client-to-server: an optional API for users posting and reading on your server (you likely already have your own API; you can bridge to it).

When you add ActivityPub, your app gains:

  • Cross-server discovery via WebFinger handles like @user@yourdomain.
  • Delivery of posts and replies to followers on other servers.
  • Social graph maintenance that syncs follow/undo, blocks, and more.
  • Portability features like account moves and export/import (if you choose to support them).

Importantly, ActivityPub is not a monolith. Different servers implement overlapping subsets and extensions. Your job is to support the common core, handle edge cases gracefully, and maintain clear safety and performance boundaries.

Choose an Architecture That Fits Your App

Three implementation shapes

  • Adapter gateway: Keep your existing app intact. Add a thin federation service that maps your internal objects to ActivityStreams JSON and handles inbox/outbox HTTP endpoints. This is the fastest path for mature apps.
  • Native-first: If you’re building from scratch, store ActivityStreams-like models directly. You’ll spend less time transforming data later, at the cost of learning the vocabulary upfront.
  • Sidecar: Deploy federation as a microservice next to your app. It interacts via queues or events and can scale independently (useful for high-fanout accounts).

Minimal viable federation (MVF)

For a stable launch, aim to ship this core set:

  • Discovery: WebFinger for @user@domain, actor JSON, NodeInfo.
  • Publishing: Outbox Create of Note with delivery to followers and mentions.
  • Receiving: Inbox handling of Follow, Accept, Undo, Like, Announce (boost), Create (replies).
  • Moderation: Domain/account blocks, report flow, content sanitization.
  • Safety: HTTP signature verification, rate limits, retries, deduplication.

Step-by-Step: Build the Server-to-Server Flow

1) Identity and discovery

  • Handles: Users should be discoverable as @name@yourdomain.
  • WebFinger (RFC 7033): Serve /.well-known/webfinger returning JRD JSON for acct:name@yourdomain with a link to the actor URL.
  • Actor: Host a JSON actor document at a stable URL. Include id, type (Person for users), preferredUsername, inbox, outbox, followers, publicKey, and endpoints.sharedInbox if you support it.
  • NodeInfo: Advertise basic server metadata (/.well-known/nodeinfo) to help other servers understand your software and capabilities.

2) Speak the dialect

  • Content types: Accept and produce application/activity+json (and application/ld+json with the ActivityStreams profile).
  • JSON-LD: Include the @context used by ActivityStreams 2.0. Avoid exotic contexts at launch.
  • Vocabulary: Start with Note objects and these activities: Create, Follow, Accept, Undo, Like, Announce, Delete, Update.

3) Post from your outbox

When a user posts, create a Create activity whose object is a Note. Include:

  • id: a globally unique URI for the activity.
  • actor: the actor URL.
  • to: include https://www.w3.org/ns/activitystreams#Public for public posts, plus specific recipients if needed.
  • cc: usually your user’s followers collection.
  • object: the Note with id, attributedTo, content (HTML), tag entries for mentions/hashtags, and inReplyTo if it’s a reply.

Deliver this activity to recipients’ inboxes. If a recipient server advertises a sharedInbox, send to that instead of individual inboxes on that domain to reduce fanout.

4) Secure delivery and retries

  • HTTP signatures: Sign POSTs with your actor’s private key. Include headers like Date, Digest, Host, and the Request-Target. Validate signatures on incoming requests using the sender’s published publicKey (on their actor).
  • Signed fetch: Some servers only return protected resources to signed GETs. Support optional signature on GET.
  • Retries: Implement exponential backoff on 5xx/timeout. Stop after a few attempts; log failures.
  • Idempotency: Deduplicate by activity.id. Ignore repeats.

5) Handle your inbox

  • Follow: When someone follows your user, queue for review or auto-accept based on account settings (public or locked). Reply with Accept or Reject.
  • Create: For incoming posts or replies, validate signature, parse the object, sanitize HTML, store, and display per your UI rules.
  • Like and Announce: Update counters and activity feeds. Consider rate limits to avoid amplification abuse.
  • Undo: Reverse a previous Follow, Like, or Announce.
  • Delete and Update: Respect deletes by tombstoning content. For updates, replace the object and bump edit metadata.

6) Mentions, hashtags, and media

  • Mentions: Convert @name@domain to <a href> links in content, and include a tag with type: Mention, href, and name. Add the mentioned actor to to or cc.
  • Hashtags: Add tag with type: Hashtag and name like #topic.
  • Attachments: Set attachment to an array of Image or Document with url, mediaType, width/height, and name for alt text. Always include alt text for accessibility.

7) Collections and pagination

  • Followers and Following: Expose as OrderedCollection with paged OrderedCollectionPage resources.
  • Outbox: If you expose it, paginate and consider access limits (many servers don’t rely on reading it heavily).
  • Caching: Use ETag and If-None-Match for actor/objects you fetch repeatedly.

Moderation and Safety You Can Actually Ship

Request verification

Discard unsigned requests. Verify HTTP signatures and check the Date header to prevent replay. Validate Digest for message integrity. Only accept objects whose actor matches the signer.

Abuse controls

  • Domain blocks: Hard-block domains that send spam, malware, or hate. Soft-block to quarantine and require manual review.
  • Account-level blocks: Allow users and moderators to block specific actors.
  • Rate limits: Per-sender and per-inbox concurrency caps to protect your queues.
  • Content warnings: Support summary on posts and a UI toggle to blur sensitive media. Honor remote servers’ sensitivity flags.
  • Reports: Implement the Flag activity or provide a bridge from your internal report tool. Send minimal context to remote moderators.

Privacy expectations

ActivityPub supports audiences via to/cc fields, but content is not end-to-end encrypted by default. Treat DMs as not confidential across domains. Offer clear privacy controls, but avoid promising secrecy you can’t guarantee. For limited audiences, only deliver to specified recipients and omit the Public collection.

HTML sanitization

Sanitize inbound and outbound content. Allow a minimal subset like <p>, <a rel=”nofollow noopener”>, and basic emphasis tags. Strip scripts, iframes, embeds, and inline event handlers. Normalize links and scrub tracking parameters where appropriate. This often eliminates a large class of phishing and XSS attempts.

Performance and Reliability Without Surprises

Fanout and backpressure

  • Queues: Put deliveries on a durable queue. Keep a small inflight limit per remote domain.
  • Shared inbox: Detect remote sharedInbox endpoints and fan-in deliveries to reduce HTTP load.
  • Concurrency: Use a per-domain worker pool to avoid stampeding a single host.
  • Backoff: Exponential backoff and jitter on failures. Drop to a dead-letter queue after N attempts for manual inspection.

Storage, IDs, and retention

  • IDs: Use stable, globally resolvable IDs (HTTPS URLs) for actors and objects. Avoid opaque sequential IDs in public URIs.
  • Dedup: Store a hash of activity IDs to prevent reprocessing.
  • Retention: Decide how long to keep remote content and thumbnails. Provide a setting for space-constrained deployments.

Networking hygiene

  • HTTP/2 with persistent connections where possible.
  • Compression (gzip/br) for payloads.
  • Time limits: Use reasonable connect/read timeouts to avoid worker starvation.
  • Well-known endpoints: Cache positive and negative lookups for WebFinger and NodeInfo.

Data Model: Map Your App to ActivityStreams

You don’t have to adopt all of ActivityStreams to federate. Map your core entities thoughtfully:

  • UsersPerson.
  • PostsNote (plain text/HTML) or specialized types if needed (Article, Image), but start simple.
  • RepostsAnnounce with the original object in object.
  • LikesLike with object pointing to the target.
  • FollowsFollow from follower actor to followee actor.

For edits, send Update with the new object. For deletions, send Delete with a tombstone. Always preserve the original id for continuity.

Accessibility and Internationalization

  • Alt text: Required for images and videos. Carry it through in the name field of attachments.
  • Language tags: Use lang on HTML content where practical. Avoid auto-translating content without clear UI controls.
  • Content sizing: Respect remote media size hints and lazy-load in your UI.

Developer Experience and Testing

Local dev tips

  • Tunnel: Use a public tunnel (e.g., ngrok) to receive remote callbacks during development.
  • Fixture servers: Test against popular implementations like Mastodon and GoToSocial. Create throwaway accounts on your own instances.
  • Compliance checks: Validate your WebFinger, actor documents, HTTP signatures, pagination, and security headers.
  • Logging: Log every inbound/outbound activity with request IDs and signature status. Redact personal content.

Launch checklist

  • Deliver a signed Create Note to a known Mastodon account. Confirm it appears and threads correctly.
  • Receive and Accept a Follow. Send a test post and verify your follower receives it.
  • Test Like, Announce, Undo, Delete, and Update with common servers.
  • Verify domain and account block behavior. Confirm you drop traffic cleanly.
  • Exercise retry logic by simulating remote 5xx and timeouts.

User Experience That Makes Federation Feel Simple

Federation terms are new to many users. Keep the UX familiar:

  • Plain-language handles: Show @name@yourdomain but let people copy a tap-to-share link.
  • One-tap follow: If a remote server supports it, auto-redirect to the user’s home instance for confirmation. Else, show a simple “paste your handle” box.
  • Threading: Thread by inReplyTo and object.id. Collapse long discussions; fetch on demand.
  • Block/report flows: Mirror your local tools for remote actors and domains.
  • Privacy notes: A small banner that reminds users: “Direct messages across servers are not end-to-end encrypted.” This builds trust.

Roadmap: Grow Beyond the Basics

  • Account moves: Support the Move flow so users can migrate to a new handle with redirect and follower transfer.
  • Polls: Add Question objects with oneOf/anyOf and tallying.
  • Groups: Consider Group actors for communities and mailing-list-style delivery.
  • Emoji reactions: Treat as custom Like variants or extensions; keep compatibility by also emitting a standard Like.
  • Collections export: Allow users to export followers and posts for portability.
  • Rate-aware fanout: Learn per-domain capacities and schedule accordingly.

Common Pitfalls and How to Avoid Them

  • Over-scoping the first release: Ship the MVF. Fancy objects can wait.
  • Ignoring signature verification: You’ll become a spam relay. Always verify, always validate actors.
  • Assuming DMs are private: They aren’t. Communicate this clearly.
  • Not sanitizing HTML: Sanitization is non-negotiable.
  • Hardcoding server quirks: Prefer robust defaults and feature detection over per-domain hacks. Keep a small compatibility layer if needed.

How This Fits Your Business

Federation is not a surrender of your product. It is a distribution and trust surface you control. You choose what to federate, how to moderate, and which extensions to adopt. Federation can unlock growth through interoperability, lower switching costs for users, and resilience against outages or policy changes elsewhere.

Start with a specific user story—“followers on other servers can subscribe to our posts and reply”—and expand when it shows value. Meanwhile, keep your own first-class features and business model. Federation adds network effects; it doesn’t remove differentiation.

Summary:

  • ActivityPub lets your app publish and receive social content across domains using actors, activities, and JSON-LD.
  • Start with an adapter gateway or sidecar service that implements WebFinger, actor JSON, outbox publishing, and inbox handling.
  • Support the core activities: Create, Follow, Accept, Undo, Like, Announce, Delete, Update.
  • Secure all inbound and outbound requests with HTTP signatures; verify senders and apply strict rate limits.
  • Use shared inboxes, queues, retries, and idempotency to scale delivery and keep it reliable.
  • Sanitize HTML, implement blocks and reports, and set clear expectations for privacy (no E2EE by default).
  • Ship a Minimal Viable Federation first, then add polls, groups, account moves, and richer objects.
  • Treat federation as a product surface you own—it increases reach without erasing your differentiation.

External References:

/ Published posts: 117

Andy Ewing, originally from coastal Maine, is a tech writer fascinated by AI, digital ethics, and emerging science. He blends curiosity and clarity to make complex ideas accessible.