Skip to content

Instantly share code, notes, and snippets.

@trwnh
Created September 26, 2026 23:13
Show Gist options
  • Select an option

  • Save trwnh/86bad8a3233cf5881eaac63a170bd1a3 to your computer and use it in GitHub Desktop.

Select an option

Save trwnh/86bad8a3233cf5881eaac63a170bd1a3 to your computer and use it in GitHub Desktop.

Mastodon protocol contains many departures from ActivityPub specification, mostly in the form of additional requirements.

The point is that the following is a non-zero list of differences. Compliant ActivityPub gets dropped by Mastodon all the time. I'm probably missing things here, since there are a ton of issues I haven't looked through, but this is what I could find just reading through the spec. I maintain that reading https://docs.joinmastodon.org/spec/activitypub/ is more useful than reading https://www.w3.org/TR/activitypub/ if your goal is to talk to Mastodon.

Mastodon protocol's differences from ActivityPub

  • The primary unit of content is a Note, not an Activity.
  • You MUST compact your documents against the same context as Mastodon's internal context. URIs are not expanded to become unambiguous.
  • Actors MUST have a type of Person, Group, Organization, Application, Service. (AP says that actors can have any type.)
  • Actors MUST have a preferredUsername (instead of MAY). Performing a WebFinger query for acct:{preferredUsername}@{origin(id)} MUST result in a rel=self link back to the id with an activity-compatible IANA type.
  • You MUST accept application/activity+json (instead of SHOULD).
  • You can't GET the inbox.
  • You can't POST to the outbox.
  • If you GET the outbox, it leaves out Update activities. Instead, the old activity is silently modified, and you can't detect this without paging through the entire outbox all over again.
  • Activities delivered to inboxes are not verified by dereferencing the id as they SHOULD. Instead, the HTTP POST request MUST be signed. (The details of this signature and the associated key are different between Mastodon protocol versions.)
  • Activities are discarded if their type is not Create, Announce, Delete, Follow, Like, Block, Update, Undo, Accept, Reject, Flag, Add, Remove, Move, QuoteRequest, or FeatureRequest.
  • Activities are discarded if their object is not a Note, Question, Image, Audio, Video, Article, Page, or Event.
  • Activities are discarded if the id's host and the object's host do not match.
  • Activities are discarded if a Tombstone exists.
  • Activities are discarded if no one follows the actor, it wasn't fetched directly, it wasn't requested through a relay, it doesn't respond to a followed account, and it doesn't address any local accounts.
  • to vs cc Public is semantically significant for their "unlisted"/"quiet public" feature.
  • Public is not serialized as as:Public. (To be fair, this one is an AP spec bug -- see w3c/activitypub#404 (comment) for more details.)
  • audience is ignored and not considered when calculating Mastodon's "scope" property or distribution to actors.
  • Create activities result in syndication of the object as a "post" or Status. The Create activity is not stored.
  • Update activities are rejected if the object is more than 1 day old and the object is not already known (and stored as a Status).
  • Reject Follow at any time will destroy a follow relationship.
  • Reject Follow is dropped when the object is not an embedded Follow. activity. (This means that referencing a Follow activity will not work. In fact, the id is ignored entirely!)
  • Add activities are dropped unless related to "featured" collections.
  • Remove activities are dropped unless related to "featured" collections.
  • Undo activities must have an object whose type is Announce, Accept, Follow, Like, or Block.
  • Block activities are federated.
  • Various size limits are imposed on payloads.

Mastodon protocol's schematic constraints over ActivityStreams

See also https://gist.github.com/trwnh/d2f6fb1c87465baab8231427013a36a8

  • to is an array.
  • cc is an array.
  • items is an array.
  • attachment is an ordered list.
  • Depending on the activity type, the object MUST be referenced by id instead of embedded.
  • Likes and shares counts are only obtained from embedded collections and not from referenced collections.
  • Null values are serialized instead of dropped (e.g. for summary).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment