# Sentry beforeSend: scrub PII without silently dropping everything

## The callback

```js
Sentry.init({
  dsn: "___PUBLIC_DSN___",
  beforeSend(event) {
    if (event.user) {
      delete event.user.email; // keep the id, drop the address
    }
    return event; // ALWAYS return the event, or return null to drop deliberately
  },
});
```

The classic bug: a `beforeSend` that mutates the event but forgets to return it. In JS that returns `undefined`, which the SDK treats as drop. Events vanish with no error. If volume craters after adding `beforeSend`, read the function first.

## Prefer category control over hand-scrubbing (v11)

`sendDefaultPii` is replaced by `dataCollection`, with per-category switches:

```js
dataCollection: {
  userInfo: false,
  cookies: false,
  httpBodies: [],
  urlQueryParams: { deny: ["forwarded", "-ip"] },
}
```

Warning from the migration guide: the v11 default collects MORE than v10 did (user info, cookies, request/response bodies, genAI inputs/outputs). If you relied on the v10 restrictive default, set the baseline explicitly or you start shipping data you never approved.

## The built-in denylist

The SDK always scrubs values whose keys look sensitive (auth, token, secret, password) and sends `[Filtered]`. Treat it as best effort: it matches on the key name, so a credential in a field named `customer_ref` sails through. Name sensitive fields like they are sensitive, or scrub them in `beforeSend`.

## Layer the defenses

1. `dataCollection` categories: collect only what you need.
2. `beforeSend`: surgical redaction of the rest.
3. Server-side scrubbing in project settings: backstop for anything the SDK missed.

Cheaper filters first: `ignoreErrors` for known noise and `denyUrls`/`allowUrls` for third-party script errors cost less than a `beforeSend` that parses every event.