This is part of a series examining alternatives for programmers to create software for the Open Social Web!!!

Fediverse dev: Step 1!

I have tried to break into the Fediverse1 world a couple of times already and failed to be comfortable as a developer in there.

I think I have failed to enter the space mostly because:

  1. I was late to the party -- i.e., there is too much happening and I got cross-eyed!

  2. ActivityPub is documented in confusing ways -- i.e., the SPECs are a hard to parse documents and it is hard to find straightforward documentation.

  3. I approached it in ambitious ways. (I thought I could contribute to already going on software, which slowed me down to a halt.)

This time around, I have the advantage of, 1. having tried, 2. having learned some bits and pieces, 3. scoped my hopes down (at least, for starters.)

I have not only learned a bunch, but also was encouraged by those brave souls that have been building in this space, who are friendly and welcoming, especially those that created more approachable maps of the space (I am looking at you Darius, Bengo, Evan, and others).

In the beginning...

... there was activitypub.rocks and this clear diagram:

image

Quick facts:

  • Actors create activities, which are actions over posts, like create, update, and delete;
  • Activities are added to an actor's outbox for consumption by others, like followers;
  • If an actor follows other actors, Activities may be added to their inbox;
  • All of these ActivityPub entities are JSON documents reachable by HTTP URL's.

The simplest ActivityPub server?

That to make it all happen: I have a website and I want to "make it part of the Open Social Web" using ActivityPub.

For this purpose, my website can be seen as just a bunch of HTML documents identifiable by paths under https://nigini.me

like:

  • /about
  • /news/2025-08-31-dweb-portland
  • /blog/1-welcome

How can I turn my website into an ActivityPub Actor?

As I said before, everything in ActivityPub happens around JSON documents accessible through HTTP, so, here is a valid Actor2 for my website (which you can also retrieve live with curl -H "Accept: application/activity+json" https://nigini.me/activitypub/actor:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Person",
  "id": "https://nigini.me/activitypub/actor",
  "preferredUsername": "blog",
  "name": "nigini's blog",
  "summary": "My personal blog with federated posts",
  "inbox": "https://nigini.me/activitypub/inbox",
  "outbox": "https://nigini.me/activitypub/outbox",
  "followers": "https://nigini.me/activitypub/followers",
  "following": "https://nigini.me/activitypub/following",
  "url": "https://nigini.me/blog"
}

But, nigini, how do others on the web find this actor? Good question: here, AP decided to re-use a specification called Webfinger, which allows for any http domain to point to associated identities. In our case, when an AP client or server needs to find @blog@nigini.me they know they have to ask for the resource *acct:blog@nigini.me to the domain's webfinger endpoint, which must be: /.well-known/webfinger*. So, when someone (including you, try it!) gets https://nigini.me/.well-known/webfinger?resource=acct:blog@nigini.me, they should see something like:

{
  "links": [
    {
      "href": "https://nigini.me/activitypub/actor",
      "rel": "self",
      "type": "application/activity+json"
    }
  ],
  "subject": "acct:blog@nigini.me"
}

How can I create and publish activities?

The rest, you may have figured already, follows from the fact that all relevant endpoints are listed in the Actor's document. As we already learned at the top of this text, if you want to publish activities, you need to create them as part of the outbox, in my case: https://nigini.me/activitypub/outbox

(you can curl that endpoint using the same command for the actor endpoint.) No surprises here, what a client gets yet another JSON file with a list of activities like this:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://nigini.me/activitypub/outbox",
  "orderedItems": [
    {
      "actor": "https://nigini.me/activitypub/actor",
      "id": "https://nigini.me/activitypub/activities/create-20250914-220655",
      "object": "https://nigini.me/activitypub/posts/20250914-220655",
      "published": "2025-09-14T22:06:55Z",
      "type": "Create"
    }
  ],
  "totalItems": 1,
  "type": "OrderedCollection"
}

The server, what about the SERVER?

Well, I promised that you'd have the simplest ActivityPub server possible... So here it is:

In one line: I created a Python+Flask app that has the endpoints explained above, where all of them simply read and return the needed JSON document from my file system!

nigini.me_ap-code

To prove that I am not making this up, as soon as I ran that code (and correctly associate it with my domain) I was able to see the AP Actor from my favorite Fediverse client (try it, search for @blog@nigini.me from your AP client):

nigini.me_ap-exists

Can people follow me and see my posts already?

Nah, not with this code! So you caught me lying: This is NOT a fully functional AP server!!!

You probably realised that we have not implemented the inbox endpoint and nothing related to "managing" activities! For instance, you can see on the image above that the client can't see any "Posts" and that the button on the bottom-right says: "(Follow) Requested. !?!?!"

Here is the deal: this post is getting too long, you are likely tired, and so am I. What if we wrap up this here and I you can check the second part whenever you are ready! (OR, you can go follow my blog so you get notified when it is out! Wait, does this work already!?!?!? 🤭)


  1. By the way, I call the Fediverse all the cool Federated Social Software that exists because of the creation of the ActivityPub protocol (even those who federate over bridges, like Bluesky/AT-Proto). There are different interpretations of the term, and even if there is A Fediverse or many. There is, though, no dispute to the fact that ActivityPub is a corner stone of the Fediverse phenomenon. 

  2. To learn about what an Actor should look like, you can check the spec, but if you screen it, you can see that it is basically a list of pointers and metadata about who this actor is! 

#Fediverse #ActivityPub #OpenSocialWeb