Your browser contains Google DRM

"Web Environment Integrity" is a Google euphemism for a DRM that is designed to prevent ad-blocking. In support of an open web, this website does not function with this DRM. Please install a browser such as Firefox that respects your freedom and supports ad blockers.

Please note that although other browsers such as Vivaldi, Opera, Microsoft Edge, Brave, and Chromium exist, they are all built from the same Google Chromium codebase and all inherit the problems of Google's web dominance. The only real options outside of Chrome are Firefox and Safari.

What is Public?

Foreword: In this post I mention Mastodon by name a couple times because that is the primary software I use to access the ActivityPub network. Please do not see this as a conflation of Mastodon with "The Fedi."

Yesterday I became aware of a project that aims to bridge ActivityPub and ATProto together by acting as a traditional ActivityPub server, as well as an ATProto PDS. This is a reasonable approach from a technical perspective. It will behave as expected of a native implementation on each side, while proxying users and posts through.

But there's a disconnect between what Public means on each side of the bridge, and I'd like to take some time to dig into what that word means. While this discussion will get somewhat technical, there are reasons for the distinction after all, I'm not going to go in depth into either protocol. We'll try to stick to a higher level view of each network.


What the heck is ATProto? It's likely that more folks on Mastodon know about ATProto than folks on Bluesky, but there's certainly folks on both platforms that don't know about ATProto. ATProto is the federation protocol that Bluesky will be implementing eventually. It will enable Bluesky to exist within a wider network of services that operate independently of eachother, but still enable ease of discovery and "seamless integration." ATProto is the reason why everything on Bluesky is public. The protocol works by giving every participating service full access to everything a user does, including Posts, Follows, Followers, Blocks, Likes, etc.

ATProto is designed to be maximally discoverable. This works by having large central services that are responsible for collecting the data from all known users, and those central services provide mechanisms to subscribe to all the user data they know about. "The Firehose." This model hasn't been deployed widely in production because Bluesky itself has not enabled ATProto, and so there's no concrete data for how this model will pan out.

For those of you on Bluesky surprised by the idea that Bluesky might federate, I want you to know this was always the plan. From when Jack first mentioned Bluesky when he still owned Twitter, federation was always the plan.


ActivityPub has been around for some years now. It is famously the protocol that Mastodon uses to federate. In ActivityPub, each participating server is responsible for making their posts and users known to the wider network. There's no central discovery or publishing service like in ATProto, although relays exist to fill a similar niche. In ActivityPub, there's no prescribed mechanism to denote what is public and what is not public, so implementations began relying on convention to signal to each other how public a given post should be. In Mastodon's model there are four varying levels of "public-ness" that posts can have.

  1. Direct - This post is only visible to mentioned users
  2. Followers Only - This post is only visible to mentioned users, and users that follow the poster
  3. Unlisted - This post is visible to anyone, but is left out of discovery mechanisms
  4. Public - This post is visible to anyone, and is included in discovery mechanisms

In order for this model to work, all participating services must agree on these privacy levels meaning what they do. It is possible for a malicious or malfunctioning ActivityPub implementation to improperly treat a post as more public than it was intended to be, resulting in reach beyond the intended audience. In order for this to happen, however, the post must first reach the bad implementation for it to be rebroadcast. Direct messages are not likely to be made public, since it would require one of the parties in the thread to exist on a malicious server. I assume that most Direct messages happen between parties that know each other and are using compliant impelementations.


As I mentioned above, ActivityPub has a concept of "relays." These are opt-in mechanisms to improve discoverability of posts. ActivityPub servers can "subscribe" to relays of their choosing, and when they do so, they send all future public posts they host to the relay. The relay in turn broadcasts all those posts to the other subscribed servers. This provides a similar function to the central services in ATProto, but in ActivityPub there is no default relay, and relays are generally operated at small scales. They also don't generally have a "public feed" that anyone can subscribe to, although that's not a huge barrier to entry for a sufficiently motivated programmer.

I personally maintain an ActivityPub relay implementation called AodeRelay, and I host an invite-only version of it for furry and adjacent servers to share their posts to each other. In order for a server to join my relay, that server's administrator needs to contact me to request permission to join. I haven't yet said no to a request, but just having that option is nice. As a relay administrator, I am responsible for the content my relay is forwarding. I want my relay to remain useful to the servers that subscribe to it, and if my relay starts putting unwanted content into people's feeds, it is no longer useful.

So What is Public?

This is where we really get to compare the two models. Public in ATProto is everything. Every post. Every Like. Every Follow. Every participating ATProto service can be made aware of any activity on ATProto in real time. All user history is publicly available to anyone who looks. In ActivityPub only Some Things are public, and even then, there's far less reach for things that are public. There's no mechanism to subscribe to All Public Things, and often times even public things are only shared between one or two participating servers. Public means two different things in these two different networks.

I have mused in the past about direct ATProto integration in Mastodon. I think it's possible, and I think it's even a good idea to pursue. It would give mastodon users more reach if they want it. My prefered implementation of this would be the introduction of a fifth privacy setting.

  1. Direct - This post is only visible to mentioned users
  2. Followers Only - This post is only visible to mentioned users, and users that follow the poster
  3. Unlisted - This post is visible to anyone, but is left out of discovery mechanisms
  4. Public - This post is visible to anyone, and is included in discovery mechanisms
  5. Super Public - This post is visible to anyone, and is included in discovery mechanisms, and is actively broadcast to literally anyone who happens to be listening on ATProto

Super Public is inherently a superset if Public. Not only can anyone see the post, and not only is the post used to help users find each other and sent to relays and able to be forwarded farther in the network, but it is sent directly to every single service that is listening to ATProto's firehose. It greatly improves reach over just the Public option that Mastodon currently has, but that comes at the cost of privacy.

As it stands, Public posts on Mastodon (and other compliant ActivityPub impelementations) are still somewhat private. Sure anyone can see them, but realistically who will? Someone happening to check the federated timeline on one of the 100 servers subscribed to my relay when I make the post? My followers? If nobody boosts my public post then the total number of views it might get is probably 20. And certainly 3rd parties, who scrape and aggregate posts to gain more insight into users, are far less likely to see even my public post on ActivityPub than any given post on ATProto.

And you don't like the bridge?

No I don't like the bridge. I've already requested that my accounts be opted out, and provided a suggestion for a middle ground that enables anyone to opt in at any time for any specific post. From the ATProto side, bridging posts into ActivityPub comes at no additional disadvantage. All their data is public already, and trivially accessible to anyone who cares to look. But from the ActivityPub side, the bridge is introducing a new level of discoverability to a network that thusfar hasn't had such a concept.

I think it's critically important that developers of bridge software like this recognize that what they are doing is novel. Developers of bridge software need to acknowledge that they are changing the experience of ActivityPub users by creating these bridges, even if nobody ever interacts with them across the bridge. ActivityPub users need to understand as well that their reasonable expectations of privacy can be violated at any moment by implementations such as this ATProto bridge and the folks who would build and deploy such services.

Extra Thoughts in no particular order

  • I tried not to make this post about Bluesky and Mastodon themselves, but to talk specifically about the nature of the protocols involved.
  • I have some experience building ActivityPub software outside of AodeRelay. I experimented with a request-to-federate model in an image gallery platform in 2021
  • Mentioning Jack Twitter isn't super important. From what I've gathered he's not very involved in Bluesky or ATProto anymore.
  • There exist bridges from ActivityPub to other platforms already (such as Nostr). I have these bridges blocked from my mastodon server, not for privacy reasons but for moderation reasons.