FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
paulkinlan
paulkinlanpostherous
https://posthero.us - an email powered blogging system
Public
Like
6
postherous
Home
Code
10
backend
3
frontend
1
shared
2
ACTIVITYPUB.md
README.md
SETUP.md
E
email.ts
H
test-activitypub-inbox.ts
H
test-activitypub.ts
H
test-publish.ts
Branches
1
Pull requests
Remixes
4
History
Environment variables
9
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data โ€“ all from the browser, and deployed in milliseconds.
Sign up now
Code
/
ACTIVITYPUB.md
Code
/
ACTIVITYPUB.md
Search
7/10/2025
Viewing readonly version of main branch: v107
View latest version
ACTIVITYPUB.md

ActivityPub Implementation Guide

This document explains the ActivityPub and WebFinger implementation in the Email Blog platform.

๐ŸŒ Overview

ActivityPub is a decentralized social networking protocol that allows your blog to be discovered and followed from Mastodon, Pleroma, and other federated social networks. WebFinger is the discovery mechanism that allows users to find your blog using familiar @username@domain.com syntax.

โœ… Implemented Features

WebFinger Discovery

  • Endpoint: /.well-known/webfinger
  • Formats Supported:
    • acct:blog@your-domain.com
    • https://your-domain.com/actor
  • Response: JSON Resource Descriptor (JRD) format
  • CORS: Enabled for cross-origin requests

ActivityPub Actor

  • Endpoint: /actor
  • Type: Person
  • Username: blog
  • Content-Type: application/activity+json

ActivityPub Collections

  • Outbox (/outbox): Published blog posts as ActivityPub Create activities
  • Followers (/followers): Collection of active followers (real data)
  • Following (/following): Collection of accounts being followed (placeholder)
  • Inbox (/inbox): Processes ActivityPub activities (Follow, Unfollow, Like, Announce, Create)

Activity Processing

  • Follow Activities: Adds followers to database, sends Accept response
  • Unfollow Activities: Removes followers from database
  • Like Activities: Tracks likes per post, displays counts
  • Announce Activities: Tracks shares/boosts per post, displays counts
  • Create Activities: Tracks replies to posts, displays counts

Database Storage

  • Followers Table: Stores follower information (actor ID, username, domain, inbox, etc.)
  • Activities Table: Stores all received activities (likes, shares, replies)
  • Activity Counts: Real-time counting and display on post pages

๐Ÿ”ง Configuration

Environment Variables

# Optional: Set a custom domain for ActivityPub ACTIVITYPUB_DOMAIN=your-custom-domain.com

If not set, the system will automatically detect the domain from the request headers.

๐Ÿš€ Usage Examples

Following from Mastodon

  1. Using WebFinger format: Search for @blog@your-domain.com in your Mastodon client
  2. Using direct URL: Paste https://your-domain.com/actor in the search box

Testing WebFinger

# Test with acct format curl "https://your-domain.com/.well-known/webfinger?resource=acct:blog@your-domain.com" # Test with direct URL format curl "https://your-domain.com/.well-known/webfinger?resource=https://your-domain.com/actor"

Testing ActivityPub Endpoints

# Get actor document curl -H "Accept: application/activity+json" https://your-domain.com/actor # Get outbox (published posts) curl -H "Accept: application/activity+json" https://your-domain.com/outbox # Get followers collection curl -H "Accept: application/activity+json" https://your-domain.com/followers

๐Ÿ“‹ WebFinger Response Format

{ "subject": "acct:blog@your-domain.com", "aliases": [ "https://your-domain.com/actor", "https://your-domain.com/" ], "properties": { "http://schema.org/name": "Email Blog" }, "links": [ { "rel": "http://webfinger.net/rel/profile-page", "type": "text/html", "href": "https://your-domain.com/" }, { "rel": "self", "type": "application/activity+json", "href": "https://your-domain.com/actor" }, { "rel": "http://ostatus.org/schema/1.0/subscribe", "template": "https://your-domain.com/authorize_interaction?uri={uri}" } ] }

๐Ÿ“‹ ActivityPub Actor Format

{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" ], "type": "Person", "id": "https://your-domain.com/actor", "preferredUsername": "blog", "name": "Email Blog", "summary": "A blog powered by email publishing", "url": "https://your-domain.com", "inbox": "https://your-domain.com/inbox", "outbox": "https://your-domain.com/outbox", "followers": "https://your-domain.com/followers", "following": "https://your-domain.com/following", "publicKey": { "id": "https://your-domain.com/actor#main-key", "owner": "https://your-domain.com/actor", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----" } }

๐Ÿ”„ How Posts Become Activities

When you publish a blog post via email, it automatically becomes available in the ActivityPub outbox as a Create activity:

{ "@context": "https://www.w3.org/ns/activitystreams", "type": "Create", "id": "https://your-domain.com/post/my-post#create", "actor": "https://your-domain.com/actor", "published": "2024-01-01T12:00:00Z", "object": { "type": "Note", "id": "https://your-domain.com/post/my-post#note", "attributedTo": "https://your-domain.com/actor", "content": "<h2>My Post Title</h2><p>Post content...</p>", "published": "2024-01-01T12:00:00Z", "url": "https://your-domain.com/post/my-post", "to": ["https://www.w3.org/ns/activitystreams#Public"] } }

๐Ÿšง Current Limitations

  1. No HTTP Signatures: Authentication is not yet implemented
  2. No Follow Processing: The inbox doesn't process Follow activities yet
  3. No Push Notifications: New posts aren't automatically pushed to followers
  4. Placeholder Collections: Followers/following collections are empty
  5. No Public Key: The public key in the actor document is a placeholder

๐Ÿ› ๏ธ Future Enhancements

  1. HTTP Signatures: Implement cryptographic signatures for authentication
  2. Follow Management: Process Follow/Unfollow activities
  3. Push Delivery: Send new posts to followers' inboxes
  4. Database Storage: Store followers and following relationships
  5. Key Generation: Generate and manage cryptographic keys
  6. Rich Content: Support for images, mentions, and hashtags

๐Ÿงช Testing

Use the /test-activitypub.ts endpoint to verify all ActivityPub endpoints are working correctly.

๐Ÿ“š References

  • ActivityPub Specification
  • WebFinger Specification
  • ActivityStreams Vocabulary
  • Mastodon API Documentation

Your blog is now discoverable and followable from the fediverse! ๐ŸŽ‰

Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
ยฉ 2025 Val Town, Inc.