> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyreach.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Pre-conversation forms and feedback

> Gather details before a chat and feedback after it.

A web widget can collect structured input from visitors at two points: a **pre-conversation form** that runs before the chat starts, and a **post-conversation feedback** form that runs after it ends. Both are defined in the widget's config under `config.v1` and edited from the widget's **Behavior** settings. See [Creating a widget](/web-widgets/creating-a-widget) to set up the widget itself.

## Pre-conversation form

Set `pre_conversation_form` to show a form before the conversation begins. The visitor must submit it before the chat can start. When they submit, the field values are merged into the new conversation's `custom_metadata`, so they show up on the [conversation detail](/conversations/conversation-detail) alongside everything else the agent captured.

The value is a `FormDefinition`:

| Field          | Type   | Description                                                   |
| -------------- | ------ | ------------------------------------------------------------- |
| `id`           | string | Form identifier.                                              |
| `name`         | string | Internal name.                                                |
| `title`        | string | Heading shown above the form.                                 |
| `submit_label` | string | Text on the submit button (for example `Start Conversation`). |
| `fields`       | array  | The fields to collect. See [Field types](#field-types).       |

### Show once per visitor

`pre_conversation_show_once` controls whether a returning visitor sees the form again. It defaults to `true`.

When enabled, the submitted values are cached in the visitor's browser `localStorage` under the key `anyreach-widget-form-<widgetId>`, along with a hash of the form's fields:

* On a later visit, if the cached hash still matches the current fields, the form is skipped and the cached values are reused automatically.
* If you change the form's fields, the hash no longer matches, so the form is shown again and pre-filled with the previous values.

<Note>
  The cache lives in the visitor's browser, so it is per device and per browser, not per account. Clearing site data or switching browsers shows the form again.
</Note>

## Post-conversation feedback

Set `post_conversation_feedback` to collect feedback when a chat conversation ends. This runs for WebRTC chat conversations only.

| Field            | Type             | Description                                                 |
| ---------------- | ---------------- | ----------------------------------------------------------- |
| `enabled`        | boolean          | When `false`, feedback is disabled.                         |
| `thank_you_text` | string           | Message shown after the visitor submits.                    |
| `form`           | `FormDefinition` | The feedback form. Same shape as the pre-conversation form. |

### Where feedback lands

When the visitor submits, the widget posts the values to a public endpoint:

```bash theme={null}
POST /core/public/web-widgets/{id}/conversations/{conversation_id}/feedback
Content-Type: application/json

{
  "data": {
    "rating": "5",
    "comments": "Great help, thanks!"
  }
}
```

The accepted values are written to the conversation's `custom_metadata.feedback_form`, where you can read them from [conversation detail](/conversations/conversation-detail). The `data` object is keyed by field `id`.

Because this endpoint is public and unauthenticated, the server applies several guards:

| Rule                | Behavior                                                                                                             |
| ------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Single submission   | Feedback is accepted only once per conversation. A second submission returns `409`.                                  |
| Allowed fields only | Keys not matching a configured feedback field `id` are dropped. If nothing valid remains, the request returns `400`. |
| Size cap            | Payloads larger than 16 KB (serialized JSON) return `413`.                                                           |
| Feedback enabled    | If the widget has no feedback form configured, the request returns `400`.                                            |
| Ownership           | The conversation must belong to the widget, or the request returns `403`; an unknown conversation returns `404`.     |

## Field types

Both forms use the same `FormField` shape. Set `type` to one of:

| Type            | Editor label  | Description                                                                                                  |
| --------------- | ------------- | ------------------------------------------------------------------------------------------------------------ |
| `input`         | Text Input    | Single-line text field. Supports `validation` (regex) and `validation_message`.                              |
| `textarea`      | Text Area     | Multi-line text field. Supports `validation` and `validation_message`.                                       |
| `boolean`       | Yes / No      | Two-button toggle. Customize the buttons with `true_label` (default `Yes`) and `false_label` (default `No`). |
| `rating`        | Rating        | Star rating. `max_rating` sets the number of stars, from `2` to `10` (default `5`).                          |
| `single_select` | Single Select | Pick one of `options`.                                                                                       |
| `multi_select`  | Multi Select  | Pick several of `options`.                                                                                   |
| `display`       | Display Text  | Static text shown to the visitor; collects no value.                                                         |

Common field properties:

| Field                | Type                                  | Default    | Description                                                        |
| -------------------- | ------------------------------------- | ---------- | ------------------------------------------------------------------ |
| `id`                 | string                                | —          | Field identifier. Becomes the key under `custom_metadata`.         |
| `type`               | enum                                  | —          | One of the types above.                                            |
| `label`              | string                                | —          | Label shown to the visitor.                                        |
| `placeholder`        | string                                | —          | Placeholder text for `input` and `textarea`.                       |
| `required`           | boolean                               | `false`    | Whether the visitor must answer.                                   |
| `default_value`      | string / boolean / number / string\[] | —          | Pre-filled value.                                                  |
| `options`            | array of `{ label, value }`           | —          | Choices for `single_select` and `multi_select`.                    |
| `display_mode`       | `dropdown` / `buttons`                | `dropdown` | How select options render.                                         |
| `allow_other`        | boolean                               | `false`    | Adds an **Other** choice with a free-text input to a select field. |
| `validation`         | string                                | —          | Regex the value must match (`input` / `textarea`).                 |
| `validation_message` | string                                | —          | Error shown when `validation` fails.                               |

<Tip>
  Choose `display_mode: "buttons"` for short option lists you want visible at a glance, and the default `dropdown` for longer lists.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Creating a widget" icon="plus" href="/web-widgets/creating-a-widget">
    Set up the widget these forms attach to.
  </Card>

  <Card title="Conversation detail" icon="message" href="/conversations/conversation-detail">
    See where submitted form and feedback values land.
  </Card>
</CardGroup>
