# Feedback (/docs/feedback)

You keep your own feedback UI, such as an in-game "Send feedback" button, a rating after a match, thumbs up/down on a new map or a bug report form. When a player submits it, send it to RoChart. RoChart stores it, links it to the player who wrote it, and gives you one inbox you can slice by anything you know about them: *what do players on phones complain about?* or *what do new players struggle with?*

<CopyPrompt preset="feedback">
  Hand this to your coding agent. It finds your feedback form, or adds a small one, and sends submissions to RoChart.
</CopyPrompt>

## Feedback pages [#feedback-pages]

Different flows usually need different inboxes. General feedback shouldn't be mixed up with bug reports or ratings of a new map. Each **feedback page** is its own inbox, with its own counts, categories and average rating.

Every project starts with **General**. Anything sent without a `board` goes there. To add another page, click **New page** on the Feedback screen, or just start sending with a new key:

```json
{ "board": "bugs", "message": "Fell through the floor on Volcano", "category": "map" }
```

If a key doesn't exist yet, RoChart creates that page the first time something is sent to it, so wiring up a new flow needs no setup. Keys are lowercase letters, digits, `-` or `_`. You can rename a page and give it a description at any time, but its key stays the same. Deleting a page moves its feedback to General. A project can have up to 50 pages; once it has 50, feedback sent to a new key goes to General.

Each page has its own **Copy Prompt**, which tells your coding agent to connect that flow to that page.

## Send feedback [#send-feedback]

Only `message` is required.

<Tabs items={['Roblox', 'Browser SDK', 'Node / Bun', 'HTTP']}>
  <Tab value="Roblox">
    Players submit from a LocalScript through a RemoteEvent. The server sends it with `HttpService`:

    ```luau title="ServerScriptService/Feedback.server.luau"
    local HttpService = game:GetService("HttpService")

    game.ReplicatedStorage.SendFeedback.OnServerEvent:Connect(function(player, message, rating)
      if typeof(message) ~= "string" or #message == 0 then return end
      local ok, err = pcall(HttpService.PostAsync, HttpService, "https://app.rochart.co/i/feedback",
        HttpService:JSONEncode({
          token = "rc_your_project_token",
          distinct_id = tostring(player.UserId),
          message = string.sub(message, 1, 2000),
          rating = typeof(rating) == "number" and rating or nil,
          board = "general",
        }), Enum.HttpContentType.ApplicationJson)
      if not ok then warn("Feedback not sent:", err) end
    end)
    ```

    Never trust what the client sends: check types and lengths on the server.
  </Tab>
  <Tab value="Browser SDK">
    ```ts
    await rochart.feedback({
      message: 'Exporting a report loses my filters',
      rating: 2,            // any number: 1–5 stars, 0–10 NPS, 1/0 thumbs
      category: 'bug',      // your own buckets: bug, idea, billing…
      email: form.email,    // optional contact address
    })
    ```

    The current user, their groups and the current page are attached automatically. Pass `anonymous: true` to leave the user off.
  </Tab>
  <Tab value="Node / Bun">
    ```ts
    await rochart.feedback({
      distinctId: String(robloxUserId), // omit for anonymous feedback
      message: 'Please add a trading system',
      category: 'idea',
    })
    ```
  </Tab>
  <Tab value="HTTP">
    ```bash
    curl -X POST https://app.rochart.co/i/feedback \
      -H 'content-type: application/json' \
      -d '{
        "token": "rc_your_project_token",
        "distinct_id": "123456789",
        "message": "Love the new map",
        "rating": 5,
        "category": "praise"
      }'
    ```

    ```json
    { "ok": true, "id": "0193c4f2-…" }
    ```
  </Tab>
</Tabs>

It resolves with the feedback id and fails with a message if RoChart didn't accept it. Show a thank-you on success, and keep the user's text on failure so they can try again. It only needs your public project token, so you can call it from a game server or straight from a browser.

| Field | |
| --- | --- |
| `message` | What they wrote, up to 10,000 characters (required) |
| `board` | The [feedback page](#feedback-pages) it belongs to, such as `support`. Defaults to `general`. |
| `distinct_id` | Who wrote it: the player's UserId as a string. Leave it out for anonymous feedback. |
| `rating` | Any number |
| `category` | Your own bucket |
| `email` | A contact address from your form. It isn't saved on the person. |
| `url` | The page or screen it came from |
| `properties` | Anything else: place version, map, level… |
| `groups` | Groups it belongs to, such as `{ "clan": "c_42" }` |
| `uuid` | Your own id for safe retries. Sending the same id twice stores it once. |

## Who wrote it [#who-wrote-it]

With a user id, feedback lands on that person's profile and timeline, so every property, cohort and group you know about them applies. Without one, it's kept as **anonymous**.

Feedback is also recorded as a `$feedback` event (with `$feedback_board`, `$feedback_rating` and `$feedback_category`), so the rest of RoChart works on it:

- chart the **average rating** over time, broken down by category;
- build a **cohort** of people who gave a rating of 2 or lower in the last 30 days;
- put a feedback metric on a [dashboard](/docs/product-analytics/dashboards).

## Triage [#triage]

**Feedback** in the sidebar is the inbox, with new feedback first. It opens on your feedback pages. Pick one to see its feedback, or pick **All pages** to see every page together. Inside a page, click its name to jump to another one. Each item shows the player, rating, category, group and the URL it was sent from, if any.

- **Filter** by status, category, rating, text or **cohort**.
- Mark items **resolved**, or **archived** for spam and noise. RoChart records who resolved each item and when.

Agents can triage too. For example: *"Summarise this week's open feedback from players on phones, group it into themes, and archive the spam."*

## Switch it off [#switch-it-off]

Feedback is a product you can turn off in [project settings](/docs/getting-started/project-settings#products). That hides the inbox and its agent tools. Submissions are still accepted, so nothing is lost if you switch it back on.
