Moderate Poll Text
Stream moderates the text of polls as users write it: the question, the description, the options, options suggested by other users, and free-text answers. Set up a polls policy and poll writes that carry text are checked before they are stored, with no extra API calls from your app.
Poll moderation counts towards your text moderation quota.
What gets moderated
| Poll write | Texts checked | Review queue entity type |
|---|---|---|
| Create a poll | Question, description and every option | stream:v1:poll |
| Update a poll (full or partial) | The poll's texts after the update | stream:v1:poll |
| Add an option (including a user's suggestion) | The new option | stream:v1:poll |
| Edit an option | The option's new text | stream:v1:poll |
| Cast a vote with a free-text answer | The answer | stream:v1:poll_vote |
Votes on an option carry no text and are not moderated. An update that leaves every text unchanged (for example, closing the poll) is not checked either. A partial update is checked on the texts that will actually be stored.
Each review queue item is filed under the user who made the write: the poll's creator for a create, the user who made an update, the suggesting user for a suggested option, and the voter for an answer. One user has one open item per poll. A later write by that same user updates the item and replaces its payload, including poll_operation. A different user gets a separate item.
Set up a polls policy
- Navigate to the Stream Dashboard.
- Go to Moderation → Policies and create a policy with the Polls type.
- Leave the name as
defaultto createpolls:default, which applies to every poll write in the app. A named policy (polls:<name>) applies only where your server passes its key (see Use a different policy from your server). - Add the engines you want: AI text, LLM text, blocklists, regex filters and allowlists. A polls policy does not include image, video, audio or flooding.
Without a polls policy, poll writes are not moderated.
Actions
A polls policy maps each rule to one of two actions:
| Action | What happens to the write |
|---|---|
flag |
The write is stored and visible, and a review queue item is created for a moderator to review. |
remove |
The write is rejected and nothing is stored. A review queue item is still created. |
shadow, mask and mask_flag are treated as flag: the write is stored and a review item is opened. bounce, bounce_flag and bounce_remove reject the write the same way remove does, but a bounce does not open a review item. Any other action leaves the write stored.
Only that remove verdict rejects the write. If the check cannot be completed, the write is stored.
Handling a removed write
A removed write fails with HTTP status 400 and error code 73, so your app can tell the user their poll, option or answer was not accepted:
{
"code": 73,
"message": "poll moderation failed: content blocked",
"StatusCode": 400
}For server-side requests, the error's details also names what matched: action, text_harms (AI and LLM labels) and blocklists_matched. Client-side requests never receive those details.
Users with bypass_moderation set are never checked. When a polls policy applies, each text is limited to 10,000 characters. A longer text is rejected with an input error and is not checked.
Use a different policy from your server
Server-side requests can pass config_key (and config_team) on any poll write to use a named policy instead of polls:default, for example polls:kids-mode. A config_key that does not exist is rejected. The write is not checked against polls:default instead. Client-side requests cannot choose a policy: the field is ignored, so users cannot opt themselves out of polls:default.
Review poll content
Poll items appear in the review queue like any other content. The dashboard shows the live poll, marks the flagged question, description, option or answer, and shows a removed write on its own, because that text was never stored. A poll attached to a chat message is shown with that message. A poll on a feed, or one that was never posted, is shown by itself.
Each poll moderation check records what the write was and, for option writes, which option, under moderation_payload.custom:
| Field | Value |
|---|---|
poll_id |
The poll's ID. |
poll_operation |
create_poll, update_poll, add_option, update_option or answer. |
option_id |
The option an add_option or update_option write targeted. |
moderation_payload.text_ordered_keys labels each entry of moderation_payload.texts as name, description, option or answer.
Actions on poll items
| Action | Use on | What it does |
|---|---|---|
delete_poll |
stream:v1:poll |
Deletes the whole poll, with every option and vote. Only the item filed by the poll's creator can do this, including after that creator's later edit replaces the item's payload. An item filed by someone else cannot be used to delete the poll. |
delete_poll_option |
stream:v1:poll |
Deletes one option and keeps the rest of the poll. Pass option_id when the item covers the whole poll. An item for a single option already names it. |
delete_poll_answer |
stream:v1:poll_vote |
Deletes a free-text answer and keeps the poll and other votes. Supported for polls on chat messages. |
All three deletes are permanent: poll content cannot be restored. Moderators can also mark poll items reviewed, ban the user who wrote the content, or escalate the item.
delete_poll_option and delete_poll_answer refuse when the stored content no longer holds the text that was checked. A removed edit leaves the original option or answer in place, and that original is not deleted. An answer also cannot be deleted once its poll is closed, or when the poll is not on a chat message.
See Actions for how to submit them.