"[REDACTED]".
Three layers, applied in order:
Layer 1 — fields
Matches by object key (case-sensitive, deep). Whenever the walker encounters a key in this list, the entire value at that key is replaced with "[REDACTED]" — even if it’s an object, array, or deeply nested.
{ user: { ssn: "123-45-6789" } } and { customers: [{ phone: "..." }] } alike.
Layer 2 — patterns
Regex patterns applied to every string leaf in the event. Each match is replaced with "[REDACTED]" — the rest of the string is preserved.
repairs[].content and any raw input / output you’ve opted into capturing.
Layer 3 — custom
Runs last, after fields and patterns. Called once for every leaf in the event tree, with the current value and the full JSON path to that leaf.
- the value unchanged to keep it,
- a transformed value to replace it,
undefinedto drop the leaf.
Path semantics
path is an array of string segments. For { repairs: [{ role: "user", content: "..." }] }, the walker calls custom with:
path = ["repairs", "0", "role"]path = ["repairs", "0", "content"]
path.includes(...) for coarse matching or path.join(".") for precise matching like repairs.0.content.
Cycle safety
The redactor tolerates cyclic object references. Each object is entered at most once; on revisit, the walker returns"[CYCLE]" in place. You never crash, even if beforeSend enrichment accidentally creates a cycle.
Composability example
Scrub emails/SSNs by pattern, wipe specific fields by name, hash the customer ID via custom:When redaction isn’t enough
If you need to make a decision about the whole event (e.g. drop all events for a given contract, stamp a trace ID across every event), usebeforeSend. Redaction works per leaf; beforeSend works per event.
See also
Capture policy
Strip buckets of data before redaction runs
beforeSend
Last-chance transform or drop