I know that title might seem controversial, so let’s dive in. Right now, here’s the landscape of federated protocols:
- ActivityPub - The shining star of this article.
- OStatus - Mostly deprecated in favour of ActivityPub.
- Diaspora - Exclusive to Diaspora, limiting interoperability.
- Nostr - Infamous due to problematic user behaviour, unlikely to achieve significant interoperability.
- Matrix - Could theoretically support social media use-cases but currently doesn’t.
- ATProto - Technically promising, yet hampered by corporate handling and mistrust from the open-source community.
Ultimately, that leaves us with ActivityPub. Everything else either lacks widespread adoption, doesn’t support common social media scenarios, or is effectively proprietary despite being open-source. For those who prioritize open-source solutions, ActivityPub is essentially the only viable option.
The Good
While I’m about to critique ActivityPub extensively, it undeniably has strong points:
- Interoperability: The core idea is genuinely powerful. Using your Mastodon account to comment on a Lemmy post—or even reading this blog post on your preferred instance—is genuinely amazing. Different instances can display content uniquely, allowing users to interact in a way tailored to their platform.
- Human-readable JSON: While some might underestimate this, JSON’s human readability makes debugging and understanding ActivityPub interactions straightforward.
- Extensible: Custom properties and types can extend functionality beyond initial design limitations, ensuring future flexibility.
The Bad
Most issues with ActivityPub stem from one critical flaw: much of its behaviour is undefined. The core types and activities allow interactions that make little practical sense. For instance, the Like
activity should be simple—you like something. But, in ActivityPub, you can “like” another Like
activity, creating infinite loops of nonsensical interactions.
This flexibility leads to a significant problem: no two implementations behave identically. Developers resort to hacks and guesswork to interpret undefined behaviour. Ideally, ActivityPub would strictly define interactions for core types, enabling implementations (Mastodon, Lemmy, Pleroma, etc.) to focus solely on presentation or extending functionality, knowing basic interactions remain consistent across platforms.
A practical example is the confusion around private messages. Two competing methods have emerged: a custom ChatMessage
type not officially supported by ActivityPub (used by Lemmy, Pleroma and others), and an alternate “standard” using a Note
object that excludes the public audience but explicitly mentions recipients (used by Mastodon and others). This ambiguity creates compatibility nightmares.
Another example I personally encountered was a frustrating issue while implementing ActivityPub for this blog: updating a post propagated to Lemmy but not Mastodon. Despite the Update
activity being accepted, Mastodon silently rejected it unless the updated
timestamp changed—a logical but unofficial requirement. Developers must track down subtle implementation details that aren’t formally documented, significantly complicating adoption and usage.
The Ugly
Privacy is virtually non-existent. When another server federates with yours, it receives all public activities, which might seem harmless initially. However, what happens if you mistakenly share sensitive information publicly? In theory, deleting a post propagates across the network, but real-world scenarios vary greatly—from technical glitches to outright malicious actors ignoring delete requests. Ensuring robust privacy requires substantial protocol-level changes, such as introducing end-to-end encryption—something notoriously complex to implement, as evidenced by Matrix’s struggles.
Another significant flaw is impersonation vulnerability. ActivityPub itself has no built-in authentication mechanism, meaning anyone could theoretically impersonate any user. Although most implementations use the HTTP Signatures standard to address this, ActivityPub itself remains incomplete in terms of essential security features. The standard openly acknowledges:
Unfortunately at the time of standardization, there are no strongly agreed upon mechanisms for authentication.
Conclusion
ActivityPub, particularly its vocabulary rules (ActivityStreams), remains a half-finished protocol. Its effectiveness depends heavily on individual implementation choices, creating problematic discrepancies—such as the inability to reliably send private messages between Mastodon and Lemmy users. Moreover, simple human errors or software oversights can unintentionally expose private information, as recently demonstrated when new Fediverse software mishandled Mastodon-style private messages and displayed them publicly.
The solution? ActivityPub needs a clearly defined second iteration—an ActivityPub v2—that eliminates ambiguity, standardizes behaviour strictly, and provides essential security measures. Certain issues, especially privacy, may never be fully resolved within the protocol, but increased clarity and stricter rules would significantly mitigate existing risks.
This doesn’t mean we should abandon ActivityPub, but rather, we must work collectively to standardize it further, making it more secure and less error-prone.
What are your thoughts on ActivityPub? Have you developed something using it? Are you planning to? Let me know in the comments!
I think that slow evolution is essentially happening. At least that’s my hope.
Kinda, but in a really weird way, nothing is getting standardized and everything is a de-facto standard (or not, especially Mastodon devs don’t really care about the rest of Fediverse), which is not good for development.
It really depends on the goals of the various players in the field. I for my part don’t use mastodon at all and would have no problem loosing all functional connectivity to it from lemmy, the same goes for pixelfed and peertube. Now, if the respective developers see value in having these applications functionally integrated, they can and will work towards this goal. If they don’t, and apparently they do not, the implementations might diverge to the point of being incompatible. And this might be just fine, too.