How to make polls in ActivityPub network.
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.
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.
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:
oneOf
, if the poll requires choosing a single option.anyOf
, if the poll allows choosing multiple options.The value of this property MUST be an array of objects representing poll options:
type
: the Note
string.name
: the text of the poll option.replies
: the total number of votes, as a collection:
type
: the Collection
string.totalItems
: the total number of votes for this poll option.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
}
}
]
}
A vote is represented by a Note
object with the following structure:
id
: the ID of the vote.type
: the Note
string.attributedTo
: the actor that is making this vote.inReplyTo
: the ID of the Question
object.name
: the value of the name
property of the chosen poll option.to
: the author of the poll.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:
endTime
is specified).name
is not already registered (if multiple choices are not allowed).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).
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.
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.
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.