#Moderation on top of the ActivityPub vocabulary

#High level concepts

For the purpose of this document we will map the following concepts to the ActivityPub vocabulary in the following way:

#Instance and Service

An instance represents an Actor object on an ActivityPub service with the type Application or Service.

In the go-activitypub libraries, we use the following convention:

A Service actor represents an ActivityPub capable server (for our use case, it is required for it to be C2S capable). Its inbox can be used as a global inbox for the other actors belonging to it.

An Application actor represents a "frontend" to present the activitypub content to its users. It can be a web or standalone application.

An instance can belong to any of these two categories, but for the purpose of this document we will refer to the former as the "service" and to the later as the "instance".


A user represents an Actor on an ActivityPub service with the type Person. Its lifetime is most likely related to the Instance, which represents the intermediary for creating, modifying and possibly removing the user.


By convention a tag represents an Object that doesn't have a specific Type property. To scope a tag to a specific instance, we can use the tag's URL property which should point to the instance's host, or it's "attributedTo" property which should point to the instance actor.

#Moderation log

The moderation log is a list of activities that correspond to the following parameters:

  • moderation activities that users operated on objects or actors related to the instance. Activity types included here are Flag, Ignore, Block.
  • follow requests from other instances or services. Activity types included here are Follow.
  • other activities which have been effected in reply to any of the previous ones. Activity types included here are Delete, Update, Remove (from collection), Add(? to collection), Move(?).

moderation log screenshot


ActivityPub doesn't have the concept of a role that actors can fulfill. In the ActivityPub specification all actors can have the same behaviour, which is not limited in any way.

The only authorization related implication that can be deduced from the specification is that actors which are not part of an object's recipient list (and also, by convention, if the list does not include the Public ActivityStreams namespace) the actor can not view the object.

Outside of that there is no explicit mechanism of not allowing actors to operate Update, Delete, Remove, Undo, and other activity types with destructive side effects on other random activities or objects.

The common sense approach (which is already used in the go-activitypub libraries, and pretty much in all other ActivityPub enabled services out there) is to limit the operation of these activities just for the actors which are "owning" the respective objects and activities.


An actor can be said to be the owner of an activity or object if it can be found in the "actor" and "attributedTo" properties of an Activity, or in the "attributedTo" property of an Object.

However, based on the fact that ActivityPub is a federated ecosystem, besides the normative representation of an activity (which resides in the outbox of its creator) all recipients receive copies, of which it can be said that they own.

So based on this premise we can safely say that an actor "owns" all the activities that exist (as copies) in their inbox.

We can take it a little further and say that an actor owns any activity or object that is stored in a collection belonging to them, and as such can effect activities that manipulate those items in said collection.

This means they can Add/Remove/Move it from the collection, or Update, Delete it.


Due to the restrictions detailed in the previous paragraphs we need to find a way to create and assign roles for actors using a mechanism relying on the ActivityPub vocabulary but not intrinsic to the specification.

We chose to use tags to create these roles. The instance can then match them by their names (eg, #moderator, #sysop, samd).

As tags can be easily created by anyone (because they are simple objects) we need to ensure they are scoped for a single instance, and for this we can use either the URL matching mechanism for the instance's host, or some more elaborate methods using the "attributedTo" property which should point to the instance's ActivityPub IRI.

#Use cases

The initial use cases for moderation are detailed here:

#Moderation request

A user that is logged to an instance should be able to:

  • View the moderation log.
  • Flag/Ignore/Block other users, items, instances.

A user that is logged to an instance and has been tagged as #moderator should be able to:

  • View the moderation log.
  • Edit/Remove items that exist in the moderation log.
  • Add an instance wide Ignore/Block for another user that is listed in the moderation log.

A user that is logged to an instance and has been tagged as a #sysop should be able to:

  • View the moderation log.
  • Accept/Reject follow requests from other instances.
  • Tag users as #moderator when viewing their ~user profile page.
  • Add an instance wide Ignore/Block for another instance.
#Technical details about moderation

As we don't want to rely on extensions to the specification for moderating ActivityPub content, we must ensure that at least one of the actors involved in the interactions we are planning will have onwership over the activities involved.

The best choice for this is probably the instance's application actor.

This means that we need to build all of the operations we detailed in the "Use cases" section in such a way that the instance actor retains ownership over them and can be used to actively moderate them.

About this wiki

commit 52fd9d7b29f0f5610ccdbb5de1b174005c275fe3
Author: mariusor <marius@federated.id>
Date:   2023-11-10T17:49:33+01:00

Filters is a dependency of auth package too
Clone this wiki
https://git.sr.ht/~mariusor/go-activitypub-doc (read-only)
git@git.sr.ht:~mariusor/go-activitypub-doc (read/write)