> For the complete documentation index, see [llms.txt](https://docs.lassomoderation.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lassomoderation.com/automation-and-review/user-reports.md).

# User Reports

Let your users report content and other users, and triage those reports in Lasso or act on them automatically with rules.

User reports are reports your own users file about a piece of content or about another user on your platform. Your product sends each report to Lasso through the API, and they show up on the **User Reports** page for your moderators to triage. Reports are also a signal for custom moderation rules, so you can automatically flag or remove something once enough people have reported it.

{% hint style="info" %}
Lasso does not provide a report button or a reporting form. You build the reporting experience in your own product, and send every report to Lasso through the user reports endpoint.
{% endhint %}

### What you can use them for

* Give moderators a queue of everything your community is complaining about, next to what your automated moderation catches.
* Escalate on volume, for example hide content once 3 different users have reported it within 24 hours.
* Trust some reporters more than others, so a report from a moderator or a trusted user can be acted on immediately while a report from a normal user needs corroboration.
* Record notices from trusted flaggers and authorities, with the organisation's name attached to the report.
* Catch bad-faith mass reporting by looking at how many reports a user has filed.
* Track what your users report, and how fast your team resolves it, in the analytics.

### Before you start

Two things need to be in place before your product can send reports.

1. **An API key.** Create one under **Settings → API & Webhooks**. Reports are sent with the same key as the rest of the API.
2. **At least one policy category enabled for user reports.** Every report has to name a policy category, which is the reason the user picked ("Spam", "Harassment", and so on). Go to **Policies**, open a policy category and tick the **User Reports** checkbox: "Can this policy category be selected when users are reporting content or other users?". This is off by default, so a fresh workspace has no reasons your users can pick from.

While you are there, fill in the **Information** field of each of these categories. It is meant as guidance for the reporter: "This information helps users understand when to select this policy category while submitting a user report." It is returned by the API together with the category name, so you can show it in your report dialog.

<figure><img src="https://720369-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEHJJyWYjMNTzFPyCUpfR%2Fuploads%2F2gkrEL4bXSh4Lsgx7YwX%2FScreenshot%202026-07-31%20at%2010.35.19.png?alt=media&#x26;token=07842803-1b3c-42fe-9758-57fffffff7c8" alt=""><figcaption></figcaption></figure>

### Fetching the report reasons

`GET /api/v1/user-reports` returns the list of reasons your users can choose from, so your report dialog stays in sync with the dashboard instead of hardcoding a list. Only categories that are enabled **and** have **User Reports** ticked are returned.

```json
{
  "success": true,
  "policies": [
    {
      "id": "harassment",
      "name": "Harassment",
      "description": "Targeted abuse or bullying of another user."
    }
  ]
}
```

The `id` here is the **Policy Category ID** (also shown as a column on the **Policies** page). That is the value you send back as `policy_id` when the user submits the report. If your workspace has translations enabled, each category also carries a `translations` object with the name and description per language.

### Sending a report

`POST /api/v1/user-reports` records one report. Everything goes inside a `report` object:

| Field                | Required | Description                                                                                                                                                                                                             |
| -------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `policy_id`          | Yes      | The **Policy Category ID** of the reason the user picked, for example `harassment`.                                                                                                                                     |
| `reported_by_id`     | One of   | Your own id of the user filing the report. Max 100 characters. Send this **or** `reported_by`, not both.                                                                                                                |
| `reported_by`        | One of   | A user object describing the reporter, for reporters Lasso has not seen yet. An alternative to `reported_by_id`, see [Describing the reporter](#describing-the-reporter).                                               |
| `content_id`         | One of   | Your own id of the reported content. Send this **or** `user_id`, not both.                                                                                                                                              |
| `user_id`            | One of   | Your own id of the reported user.                                                                                                                                                                                       |
| `reported_by_type`   | No       | The type of the reporter: `normal`, `trusted`, `moderator`, `admin` or `testing`. Workspaces with DSA compliance can also send `state_actor`. Defaults to the type Lasso already has for that user.                     |
| `reported_by_entity` | No       | The name of the organisation the report was filed on behalf of, for example a trusted flagger. Max 255 characters. See [Reports from trusted flaggers and authorities](#reports-from-trusted-flaggers-and-authorities). |
| `extra_info`         | No       | Free text the reporter added, shown to your moderators next to the report.                                                                                                                                              |

```json
{
  "report": {
    "policy_id": "harassment",
    "reported_by_id": "user-456",
    "content_id": "comment-123",
    "extra_info": "Keeps calling me names in this thread"
  }
}
```

A successful call returns `{ "success": true }`.

Things worth knowing:

* Send **either** `content_id` **or** `user_id`, never both and never neither. Both cases return a `400`.
* Send **either** `reported_by_id` **or** `reported_by`, never both and never neither. Both cases also return a `400`.
* The **reported content must already exist in Lasso**. If Lasso does not know the content id you get a `404` with `Reported Content not found`, so sync your content before you allow it to be reported.
* The **reported user and the reporter are created automatically** if Lasso has not seen them yet. They appear as "Unknown" until you sync their real profile. For the reporter you can avoid the placeholder by sending their details in the report itself with `reported_by`.
* An unknown `policy_id` returns a `400` with `Policy not found`. Use the identifier, not the display name.
* Reports are **not deduplicated**. The same user reporting the same item twice creates two reports. If you only want one report per user per item, enforce that in your own product.
* If the reported user or content is **already hidden** in Lasso, the report is stored as handled straight away and never reaches your moderators' open list.

The endpoint is rate limited to **100 requests per minute** per workspace. See rate limits for the response headers and retry behaviour. Full request and response details are in the [API reference](https://api-reference.lassomoderation.com/group/endpoint-user-reports).

### Describing the reporter

Normally you identify the reporter with `reported_by_id`, and Lasso creates an "Unknown" placeholder when it has not seen that user before. When the reporter is not synced to Lasso yet (an anonymous visitor, or a platform that only syncs users once they become relevant to moderation), you can send a `reported_by` object instead, so the reporter is created with real information straight away.

| Field               | Required | Description                                                                             |
| ------------------- | -------- | --------------------------------------------------------------------------------------- |
| `id`                | Yes      | Your own id of the reporter. Max 100 characters.                                        |
| `name`              | No       | The reporter's display name.                                                            |
| `email`             | No       | The reporter's email address.                                                           |
| `email_domain`      | No       | The domain of the reporter's email address, if you prefer not to send the full address. |
| `phone_number`      | No       | The reporter's phone number.                                                            |
| `country_code`      | No       | Two-letter ISO 3166-1 alpha-2 country code, for example `NL`.                           |
| `ip_address`        | No       | The reporter's IP address.                                                              |
| `profile_image_url` | No       | URL of the reporter's profile image.                                                    |
| `metadata`          | No       | Custom key-value data, in the same format as on the user endpoint.                      |

```json
{
  "report": {
    "policy_id": "harassment",
    "reported_by": {
      "id": "device-8f3a2c",
      "name": "PixelPirate",
      "email": "reporter@example.com",
      "country_code": "NL",
      "ip_address": "203.0.113.42",
      "metadata": {
        "app_version": "4.2.1"
      }
    },
    "content_id": "comment-123",
    "extra_info": "Keeps calling me names in this thread"
  }
}
```

A few semantics to be aware of:

* The fields are **only applied when the reporter is created**. If Lasso already knows the user, the extra fields are ignored, so a report can never overwrite a profile you synced. Update existing users through the user endpoint.
* There is no `type` field on the object. The reporter's type comes from `reported_by_type`, the same as with `reported_by_id`.
* Use a **stable id** for anonymous reporters, such as a device id or a hashed email address, rather than a random id per report. With a random id every report creates a new user, and rule conditions that count reports `by unique users` lose their meaning.
* A reporter created from a `reported_by` object is evaluated against your user rules, the same as a user synced through the user endpoint.

### Reports from trusted flaggers and authorities

Not every report comes from a community member. Under the EU Digital Services Act, platforms also receive notices from **trusted flaggers** (organisations whose notices must be prioritised, such as consumer protection agencies and hotlines) and from **state actors** (courts and other authorities). Two fields on the report record where such a notice came from:

* `reported_by_type` marks the kind of reporter: `trusted` for a trusted flagger, `state_actor` for an authority.
* `reported_by_entity` names the organisation itself, for example `Acme Consumer Protection`.

{% hint style="info" %}
The `state_actor` reporter type is only available on workspaces with DSA compliance enabled. Without it, sending `reported_by_type: "state_actor"` returns a `400` with `Reporter type 'state_actor' requires the DSA compliance feature`. The other reporter types and `reported_by_entity` work on every workspace.
{% endhint %}

```json
{
  "report": {
    "policy_id": "illegal-content",
    "reported_by_id": "trusted-flagger-acme",
    "reported_by_type": "trusted",
    "reported_by_entity": "Acme Consumer Protection",
    "content_id": "comment-123",
    "extra_info": "Notice under Article 16 DSA"
  }
}
```

The entity travels with the report everywhere it appears: the reports pages show it next to the reporter (for example "Trusted flagger: Acme Consumer Protection", or "State actor: ..." for authorities), it is a column in the CSV export, and it is included in the `HandleReports` webhook payload as `reporter_entity`.

A few practical notes:

* Use one stable `reported_by_id` per organisation (such as `trusted-flagger-acme`), so all of its notices are attributed to the same reporter and rule conditions that count reports `by unique users` behave sensibly.
* You can also set the organisation's account `type` through the user endpoint (see user moderation), so its reports default to the right type and you can leave `reported_by_type` off.
* Rules can treat these reports differently from community reports with the **Reported by** condition, for example flag anything reported by a trusted flagger or an authority immediately. See custom moderation rules.

### Handling reports in the dashboard

Reports land on the **User Reports** page in the sidebar. It has two tabs, **Content** and **Users**, each with the number of open reports. The Users tab is only visible to moderators with permission to see user reports.

Each row shows the reported item, its current status, when the report came in, the policy category the reporter picked, their extra information, who reported it, how many times the item has been reported in total, and, once resolved, who handled it.

From a row a moderator can:

* **Take a moderation action** on the reported content or user, with the same action buttons used elsewhere in the dashboard. The report is resolved automatically as soon as a decision is made.
* **Ignore the report** when nothing is wrong with the reported item.
* **Ignore all reports for this content** (or **for this user**) to clear every open report on the same item at once.
* Select several rows and use the **Ignore n reports** button to clear them in bulk.

By default the page only shows open reports. Tick **Show handled reports** to include the ones that are already resolved. Resolved rows carry an icon showing how they were closed: a green check when an action was taken, and a crossed-out eye when the report was ignored.

Reports resolve themselves whenever a moderator or a rule takes a final decision on the reported item. Allowing or removing content or a user marks every open report on it as handled and records which action did it. Flagging is not a final decision, so flagged items keep their reports open until someone decides.

Every report also appears in the activity timeline of the reported user or content, as "Reported by *user* for *policy*", together with the extra information the reporter sent. Once a report is resolved, its timeline entry carries a **Handled** or **Ignored** badge showing how it was closed.

### Reacting to reports with rules

A report triggers a re-evaluation of your custom moderation rules on the reported user or content, so a rule can act on it within seconds. The report conditions are grouped under **Reports** in the condition list:

* **Content # of Times Reported** and **User # of Times Reported**: compare the number of reports against a number you set. You can count `by unique users` or `in total`, over all time or `over period` with a window like the last 24 hours. By default every report counts, and two filters narrow that down: count reports from **any user type** or only from **specific user types** (for example only trusted users and moderators), and count reports filed under **any policy** or only under **specific policies**. For example, hide content reported by 3 or more unique users in the last 24 hours, or remove content as soon as it is reported twice under your harassment policy.
* **Content Reported By** and **User Reported By**: check whether the report came from a given type of user. A report from a moderator or an admin can be acted on immediately.
* **# of Reports Made By User**: available on user rules, compares how many reports a user has filed. Useful for catching users who mass-report others in bad faith.

The counting conditions look at every report ever filed on the item, including reports that were already handled or ignored.

Rules are also the link between reports and [review queues](/automation-and-review/review-queues.md). Reports do not create reviews by themselves, but a rule that flags a reported item will put it in front of your moderators through the normal routing rules.

### Reports in analytics

**Analytics → Reports** shows how reporting behaves over time: **Reports by Type** (content versus users), **Reports by Policy**, **Top Reporters**, **Average Handling Time** and **Reports by Decision**, which splits resolved reports into accepted (the item was removed), rejected (the item was allowed) and ignored. Analytics are updated asynchronously, so very recent reports can take a moment to appear.

<figure><img src="https://720369-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEHJJyWYjMNTzFPyCUpfR%2Fuploads%2Fjqqpw8EpMAry7skBXggn%2FScreenshot%202026-07-31%20at%2010.25.13.png?alt=media&#x26;token=d12df4c2-50f4-41fc-8fc8-54e19cf17503" alt=""><figcaption></figcaption></figure>

The users list also has **# Reported** and **# Reports Made** columns, so you can sort your user base by who gets reported most and who reports most.

### Reports and webhooks

There is no webhook for an incoming report, because a report on its own is not a moderation decision. Your platform hears about the outcome instead: whenever reports are resolved, a `HandleReports` action is delivered through webhooks, listing the reports that were closed with the policy category, the reporter and the reason each one carried.

Its `resolution` field tells you how the reports were closed: `actioned` when a moderation action resolved them (the resolving action is embedded in the payload, and is usually delivered in the same webhook call), or `ignored` when a moderator dismissed them without taking an action. That means your platform can, for example, notify reporters about what happened to their report.

See the **Report Actions** example on the webhooks page for the full payload.
