beforeSend is the last thing that runs before an event enters the batch queue. It sees the event after capture gating and redaction, so by the time it fires the shape is final.
Signature
- Return the event (unchanged or mutated) to keep it.
- Return
nullto drop it entirely — it never hits the queue, never hits the network. - Throw — the exception is routed through
onError; the event is dropped. A bad hook can never break the contract flow.
beforeSend vs redact.custom
Both give you a final say, but at different granularity:
redact.custom | beforeSend | |
|---|---|---|
| Called per | every leaf value | every event |
| Sees | one value + its JSON path | the whole event object |
| Can drop | one field (return undefined) | the whole event (return null) |
| Good for | scrubbing PII in place | correlation, routing, filtering |
beforeSend makes event-level decisions.
Recipes
Drop noisy contracts
Enrich with a trace ID
Hash the raw output before it leaves
Rate-limit events per contract
Errors inside beforeSend
If your hook throws, the event is dropped and onError fires with the thrown value. The contract that produced the event is unaffected — the hook runs on a separate async path.
See also
Redaction
Per-leaf scrubbing
Capture policy
Strip whole buckets before beforeSend sees the event