fep

FEP-9967: Polls

Summary

How to make polls in ActivityPub network.

History

Mastodon implemented polls in 2019 (documentation).

ActivityStreams specification provides recommendations for representing questions, but these recommendations were found to be impractical and the de-facto standard differs from them.

Requirements

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC-2119.

Question object

A poll is represented by a Question object. It MUST be published with Create activity (in contrast with ActivityStreams vocabulary where Question itself is defined as intransitive activity).

A Question object is typically structured similarly to a Note. In addition to common properties such as attributedTo and content, it MUST have one of the following:

The value of this property MUST be an array of objects representing poll options:

The name of a poll option MUST be unique within a poll.

Question objects SHOULD also have an endTime property indicating the time when the poll ends. Polls without ending time are not widely supported. Some implementations use closed property instead of endTime or in addition to it (even if the poll is open). Consumers MUST process closed in the same way as endTime.

Example:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://social.example/polls/1",
  "type": "Question",
  "attributedTo": "https://social.example/actors/1",
  "to": "https://www.w3.org/ns/activitystreams#Public",
  "content": "<p>Question</p>",
  "endTime": "2024-07-17T18:18:17Z",
  "oneOf": [
    {
      "type": "Note",
      "name": "Answer 1",
      "replies": {
        "type": "Collection",
        "totalItems": 596
      }
    },
    {
      "type": "Note",
      "name": "Answer 2",
      "replies": {
        "type": "Collection",
        "totalItems": 379
      }
    }
  ]
}

Voting

A vote is represented by a Note object with the following structure:

The object MUST NOT have a content property.

This object is wrapped in a Create activity and sent to the author of the poll. If the poll is anonymous, this activity MUST NOT be delivered to anyone else.

When a poll allows multiple choices, each vote MUST be sent as a separate activity.

Example of a vote:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://social.example/votes/1",
  "type": "Note",
  "attributedTo": "https://social.example/actors/2",
  "inReplyTo": "https://social.example/polls/1",
  "name": "Answer 1",
  "to": "https://social.example/actors/1"
}

The structure of a vote is very similar to a direct reply. It can be identified as a Note with name and inReplyTo properties, but without a content property.

[!NOTE] The method of identifying votes described here is not reliable. An alternative representation is being discussed (the Respond activity).

Upon receving a vote, the author of the poll performs the following checks:

If any of these checks fails, the vote MUST be ignored.

Otherwise, the author of the poll updates the vote count for a specified poll option (the totalItems property of a corresponding replies collection).

Publishing results

When actor that published a poll receives a vote, it publishes an Update activity containing the Question object with updated results. This activity MUST be delivered to the audience of the poll and to every actor that voted in the poll.

The embedded Question object MUST have an updated property.

Editing options

The type of a poll (single choice / multiple choices) and its options might be changed at any time. In that case the author of the poll MUST reset the vote counts.

References

CC0 1.0 Universal (CC0 1.0) Public Domain Dedication

To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.