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

# Data Scrubbing

> Redact sensitive text from incoming data with org-configurable rules

Data scrubbing lets you define rules that redact sensitive text from data as Modem ingests it. Rules are applied at a single ingest chokepoint **before** the data is stored, embedded, or sent to any model — covering message content, event text, the raw event archive, and every downstream prompt at once.

<Info>
  Rules apply to **new incoming data only**. They are not retroactive — data ingested before a rule was saved is unchanged — and they
  never alter anything in the source platform (Slack, GitHub, etc.). Scrubbing only affects the copy Modem stores and processes.
</Info>

Configure rules under **Settings → Data Scrubbing**. Any member can view the rules; only admins and owners can change them.

## How a rule works

Each rule has a **matcher** (what to find) and a **method** (how to redact it), and can optionally be scoped to specific channels.

```json theme={null}
{
    "name": "6-digit codes",
    "matcher": { "kind": "regex", "pattern": "\\b\\d{6}\\b" },
    "method": "replace"
}
```

## Matchers

A matcher is either a custom regular expression or a curated built-in pattern.

* **Custom regex** — `{ "kind": "regex", "pattern": "...", "flags": "i" }`. The `flags` field is optional and only accepts `"i"` (case-insensitive).
* **Built-in pattern** — `{ "kind": "builtin", "name": "email" }`. Available names: `email`, `phone`, `ipv4`, `ipv6`, `credit_card`, `ssn`, `iban`.

### Supported regex dialect

Custom patterns use a deliberately restricted dialect so a single rule can never hang the ingest pipeline:

* **No backreferences** (`\1`–`\9`).
* **No lookahead or lookbehind** (`(?=`, `(?!`, `(?<=`, `(?<!`).
* **256 characters maximum.**
* **Only the `i` flag** is configurable (the engine always matches globally).

Patterns are also run through an adversarial benchmark and rejected if they exhibit catastrophic backtracking. These limits keep redaction fast and predictable across large volumes of inbound content, and are enforced on the server when you save.

## Methods

Every match found by a rule's matcher is redacted using one of three methods:

* **Replace** — swap each match for fixed text (default `[Filtered]`; customizable per rule).
* **Mask** — replace each character of a match with an asterisk (`*`), preserving the match's length.
* **Hash** — swap each match for a short stable token. The **same value always hashes to the same token within your organization**, so you can still correlate repeated values (e.g. the same account number appearing in two conversations) without storing the raw value. Tokens never reveal the original and differ across organizations.

## Channel scoping

A rule can apply everywhere or only within specific channels:

* **Omit `channelIds`** (or select "All channels") and the rule applies org-wide to every message.
* **Provide `channelIds`** and the rule applies only to content from those channels; content with no channel is unaffected.

## Limits and propagation

* You can configure up to **20 rules** per organization.
* After you save, updated rules take effect for incoming data within **about a minute**. The settings page shows "Propagating…" until the change is live, then "Active".

## Testing and import/export

The settings page includes a **live test box**: paste sample text and see exactly how your current (even unsaved) rules would redact it, optionally against a selected channel to exercise scoping. You can also **export** your rules as a JSON file and **import** a JSON file to load rules into the editor before saving.
