# Flooding

Flood detection identifies users sending large volumes of repeated or near-duplicate messages in a short window and appends flood labels and escalated actions to the moderation response. It runs per user, per moderation policy, and covers two independent detectors that can be enabled separately or together:

- **Identical** — fires when a user sends the same message repeatedly. Comparison is exact after normalization (lowercase, punctuation and extra whitespace stripped).
- **Similar** — fires when a user sends near-duplicate messages that vary by small edits, such as typos, punctuation, or whitespace changes. Similarity is measured with a configurable strictness.

Each detector fires once the user reaches `threshold` matching messages within `time_window`.

## Configuration

Attach a `flood_config` block to a moderation policy via the [Upsert Config](https://getstream.io/moderation/docs/node/configuration/policies/#upsert-config) API. Both detectors are opt-in and can be configured with different thresholds and actions.

<Tabs>

```js label="Node.js"
await client.moderation.upsertConfig({
  key: "chat:messaging",
  flood_config: {
    identical: {
      enabled: true,
      threshold: 5,
      time_window: "30m",
      action: "flag",
    },
    similar: {
      enabled: true,
      threshold: 5,
      time_window: "30m",
      similarity_distance: 5,
      action: "remove",
    },
    allowlist: ["gg", "well played"],
  },
});
```

```python label="Python"
client.moderation().upsert_config(
    key="chat:messaging",
    flood_config=FloodConfig(
        identical=FloodIdenticalConfig(
            enabled=True,
            threshold=5,
            time_window="30m",
            action="flag",
        ),
        similar=FloodSimilarConfig(
            enabled=True,
            threshold=5,
            time_window="30m",
            similarity_distance=5,
            action="remove",
        ),
        allowlist=["gg", "well played"],
    ),
)
```

```ruby label="Ruby"
client.moderation.upsert_config(
  GetStream::Generated::Models::UpsertConfigRequest.new(
    key: "chat:messaging",
    flood_config: GetStream::Generated::Models::FloodConfig.new(
      identical: GetStream::Generated::Models::FloodIdenticalConfig.new(
        enabled: true,
        threshold: 5,
        time_window: "30m",
        action: "flag",
      ),
      similar: GetStream::Generated::Models::FloodSimilarConfig.new(
        enabled: true,
        threshold: 5,
        time_window: "30m",
        similarity_distance: 5,
        action: "remove",
      ),
      allowlist: ["gg", "well played"],
    ),
  )
)
```

```php label="PHP"
$client->moderation()->upsertConfig(new UpsertConfigRequest(
    key: 'chat:messaging',
    floodConfig: new FloodConfig(
        identical: new FloodIdenticalConfig(
            enabled: true,
            threshold: 5,
            timeWindow: '30m',
            action: 'flag',
        ),
        similar: new FloodSimilarConfig(
            enabled: true,
            threshold: 5,
            timeWindow: '30m',
            similarityDistance: 5,
            action: 'remove',
        ),
        allowlist: ['gg', 'well played'],
    ),
));
```

```go label="Go"
client.Moderation().UpsertConfig(ctx, &getstream.UpsertConfigRequest{
    Key: "chat:messaging",
    FloodConfig: &getstream.FloodConfig{
        Identical: &getstream.FloodIdenticalConfig{
            Enabled:    true,
            Threshold:  5,
            TimeWindow: "30m",
            Action:     "flag",
        },
        Similar: &getstream.FloodSimilarConfig{
            Enabled:            true,
            Threshold:          5,
            TimeWindow:         "30m",
            SimilarityDistance: 5,
            Action:             "remove",
        },
        Allowlist: []string{"gg", "well played"},
    },
})
```

```csharp label="C#"
await client.Moderation.UpsertConfigAsync(new UpsertConfigRequest
{
    Key = "chat:messaging",
    FloodConfig = new FloodConfig
    {
        Identical = new FloodIdenticalConfig
        {
            Enabled = true,
            Threshold = 5,
            TimeWindow = "30m",
            Action = "flag",
        },
        Similar = new FloodSimilarConfig
        {
            Enabled = true,
            Threshold = 5,
            TimeWindow = "30m",
            SimilarityDistance = 5,
            Action = "remove",
        },
        Allowlist = new List<string> { "gg", "well played" },
    },
});
```

```java label="Java"
client.moderation()
    .upsertConfig(UpsertConfigRequest.builder()
        .key("chat:messaging")
        .floodConfig(FloodConfig.builder()
            .identical(FloodIdenticalConfig.builder()
                .enabled(true)
                .threshold(5)
                .timeWindow("30m")
                .action("flag")
                .build())
            .similar(FloodSimilarConfig.builder()
                .enabled(true)
                .threshold(5)
                .timeWindow("30m")
                .similarityDistance(5)
                .action("remove")
                .build())
            .allowlist(List.of("gg", "well played"))
            .build())
        .build())
    .execute();
```

</Tabs>

### Fields

| Field                         | Type               | Required     | Description                                                                                                                   |
| ----------------------------- | ------------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `identical.enabled`           | boolean            | false        | Turn identical-message detection on for this policy.                                                                          |
| `identical.threshold`         | integer (2 to 100) | when enabled | Number of matching messages that triggers a flood verdict.                                                                    |
| `identical.time_window`       | string             | when enabled | Rolling window over which the counter accumulates. One of `1m`, `3m`, `5m`, `10m`, `15m`, `30m`, `1h`.                        |
| `identical.action`            | string             | when enabled | Action applied on trigger. One of `flag`, `remove`.                                                                           |
| `similar.enabled`             | boolean            | false        | Turn similar-message detection on for this policy.                                                                            |
| `similar.threshold`           | integer (2 to 100) | when enabled | Number of near-matching messages that triggers a flood verdict.                                                               |
| `similar.time_window`         | string             | when enabled | Same values as `identical.time_window`.                                                                                       |
| `similar.similarity_distance` | integer (1 to 16)  | when enabled | How close two messages must be to count as similar. Lower is stricter (fewer false positives, more misses); higher is looser. |
| `similar.action`              | string             | when enabled | Same values as `identical.action`.                                                                                            |
| `allowlist`                   | string array       | false        | Benign phrases exempted from flood detection. Up to 100 entries, up to 200 characters each.                                   |

Enabling either detector without both `threshold` and `time_window` fails validation on upsert.

## Allowlist

`allowlist` exempts benign phrases, such as game shout-outs or common greetings, from flood detection. Matching is exact after normalization (lowercase, punctuation and extra whitespace stripped), so `gg`, `GG!!!`, and `gg` with surrounding whitespace all match an entry `gg`, but a longer message like `gg buy crypto` does not.

The exemption applies only to flood detection. A phrase that both appears in the allowlist and matches a blocklist, AI text rule, or other provider is still actioned by those providers. Entries shorter than 3 characters are ignored.

## Detection Labels and Actions

When a detector fires, the moderation response reflects the verdict:

- One of the following labels is appended to `labels`:
  - `flood_identical` — identical-message detection triggered.
  - `flood_similar` — similar-message detection triggered.
- `recommended_action` is escalated to the strictest of the flood action and any other provider's action. Existing verdicts are never demoted, so a `remove` from another provider is never downgraded to `flag` by flood detection.
- `harm_type` is set to `spam` if it was not already set.

## Example

With a policy `chat:messaging` configured for `identical.threshold=3`, `time_window=30m`, and `action=flag`, three identical messages from the same user in 30 minutes will trigger the detector on the third message:

```jsonc
// First message from user "u1" on policy "chat:messaging" — no flood signal yet.
// Response: { "labels": [], "recommended_action": "keep", ... }
// Second identical message from "u1" — still below threshold.
// Response: { "labels": [], "recommended_action": "keep", ... }
// Third identical message from "u1" — threshold reached.
// Response: { "labels": ["flood_identical"], "recommended_action": "flag", "harm_type": "spam", ... }
```


---

This page was last updated at 2026-08-01T13:29:55.986Z.

For the most recent version of this documentation, visit [https://getstream.io/moderation/docs/node/configuration/flooding/](https://getstream.io/moderation/docs/node/configuration/flooding/).