# 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.

> **Warning:** 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

1. Navigate to the [Stream Dashboard](https://getstream.io/signin/?product=moderation).
2. Go to **Moderation** → **Policies** and create a policy with the **Polls** type.
3. Leave the name as `default` to create `polls: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](#use-a-different-policy-from-your-server)).
4. 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:

```json
{
  "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](https://getstream.io/moderation/docs/php/content-moderation/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](https://getstream.io/moderation/docs/php/content-moderation/actions/) for how to submit them.

---

For the most recent version of this documentation, visit [https://getstream.io/moderation/docs/php/guides/moderate-poll-text/](https://getstream.io/moderation/docs/php/guides/moderate-poll-text/).