---
title: "Scrubbing Sensitive Data"
description: "Learn about filtering or scrubbing sensitive data within the SDK, so that data is not sent with the event. You can also configure server-side scrubbing to ensure the data is not stored."
url: https://docs.sentry.io/platforms/python/data-management/sensitive-data/
---

# Scrubbing Sensitive Data | Sentry for Python

As with any third-party service it's important to understand what data is being sent to Sentry, and where relevant ensure sensitive data either never reaches the Sentry servers, or at the very least it doesn’t get stored.

These are some great examples for data scrubbing that every company should think about:

* PII (Personally Identifiable Information) such as a user's name or email address, which post-GDPR should be on every company's mind.
* Authentication credentials, like your AWS password or key.
* Confidential IP (Intellectual Property), such as your favorite color, or your upcoming plans for world domination.

We offer the following options depending on your legal and operational needs:

* filtering or scrubbing sensitive data within the SDK, so that data is *not sent to* Sentry. Configuration changes require a redeployment of your application.
* [configuring server-side scrubbing](https://docs.sentry.io/security-legal-pii/scrubbing/server-side-scrubbing.md) to ensure Sentry does *not store* data. Configuration changes are done in the Sentry UI and apply immediately for new events.
* [running a local Relay](https://docs.sentry.io/product/relay.md) on your own server between the SDK and Sentry, so that data is *not sent to* Sentry while configuration can still be applied without deploying.

Ensure that your team is aware of your company's policy around what can and cannot be sent to Sentry. We recommend determining this policy early in your implementation and communicating it as well as enforcing it via code review.

## [Personally Identifiable Information (PII)](https://docs.sentry.io/platforms/python/data-management/sensitive-data.md#personally-identifiable-information-pii)

The SDK purposefully does not send PII to stay on the safe side. This behavior is controlled by an option called [`send_default_pii`](https://docs.sentry.io/platforms/python/configuration/options.md#send_default_pii).

Turning this option on is required for certain features in Sentry to work, but also means you will need to be even more careful about what data is being sent to Sentry (using the options below).

If you *do not* wish to use the default PII behavior, you can also choose to identify users in a more controlled manner, using our [user identity context](https://docs.sentry.io/platforms/python/enriching-events/identify-user.md).

## [Scrubbing Data](https://docs.sentry.io/platforms/python/data-management/sensitive-data.md#scrubbing-data)

### [`event_scrubber`](https://docs.sentry.io/platforms/python/data-management/sensitive-data.md#event_scrubber)

You can use the `event_scrubber` configuration parameter to simplify removing sensitive data from your event payload.

The default scrubber implementation will run automatically and filter anything in the [`denylist`](https://github.com/getsentry/sentry-python/blob/4b361c5c008aec1a33cf521014edc0297fbf89c1/sentry_sdk/scrubber.py#L15-L56) from [potentially sensitive interfaces](https://docs.sentry.io/platforms/python/data-collected.md) in the event payload. These are typically security values such as passwords, authentication, sessions, cookies, and CSRF tokens.

Additionally, if `send_default_pii` is set to `False`, the scrubber will also filter from a separate `pii_denylist` that typically has PII values such as IP addresses.

```python
import sentry_sdk
from sentry_sdk.scrubber import EventScrubber

sentry_sdk.init(
    # ...
    send_default_pii=False,
    event_scrubber=EventScrubber(),  # this is set by default
)
```

You can also pass in a custom `denylist` or `pii_denylist` to the `EventScrubber` class and filter additional fields that you want. Make sure you extend the current lists if you want to use the default lists as well.

```python
from sentry_sdk.scrubber import EventScrubber, DEFAULT_DENYLIST, DEFAULT_PII_DENYLIST

# custom denylist
denylist = DEFAULT_DENYLIST + ["my_sensitive_var"]
pii_denylist = DEFAULT_PII_DENYLIST + ["my_private_var"]

sentry_sdk.init(
    # ...
    send_default_pii=False,
    event_scrubber=EventScrubber(denylist=denylist, pii_denylist=pii_denylist),
)
```

The scrubber will check parts of the event that are most likely to contain data from the denylist, like user and request data. However, by default, it will not search these recursively for performance reasons. If you want the scrubber to be recursive, initialize it with `recursive=True`.

```python
from sentry_sdk.scrubber import EventScrubber

sentry_sdk.init(
    # ...
    send_default_pii=False,
    event_scrubber=EventScrubber(recursive=True),
)
```

### [`before_send` & `before_send_transaction`](https://docs.sentry.io/platforms/python/data-management/sensitive-data.md#before-send-before-send-transaction)

The SDK provides a `before_send` hook, which is invoked before an error or message event is sent and can be used to modify event data to remove sensitive information. The SDK also provide a `before_send_transaction` hook which does the same thing for transactions. We recommend using `before_send` and `before_send_transaction` in the SDK to **scrub any data before it is sent**, to ensure that sensitive data never leaves the local environment.

Sensitive data may appear in the following areas:

* Stack-locals → The SDK picks up variable values within the stack trace. These can be scrubbed, or this behavior can be disabled altogether if necessary.
* Breadcrumbs → The SDK picks up previously executed log statements. **Do not log PII** if using this feature and including log statements as breadcrumbs in the event. The SDK will also record database queries, which may need to be scrubbed. The SDK will add the HTTP query string and fragment as a data attribute to the breadcrumb, which may need to be scrubbed.
* User context → Automated behavior is controlled via `send_default_pii`.
* HTTP context → Query strings are picked up in web frameworks as part of the HTTP request context.
* Transaction Names → In certain situations, transaction names might contain sensitive data. For example, an HTTP request transaction might have a raw URL like `/users/1234/details` as its name (where `1234` is a user id, which may be considered PII). In most cases, our SDK can parameterize URLs and routes successfully, that is, turn `/users/1234/details` into `/users/:userid/details`. However, depending on the web framework, your routing configuration, and a few other factors, the SDKs might not be able to completely parameterize all of your URLs.
* HTTP Spans → The SDK includes the HTTP query string and fragment as a data attribute, which means the HTTP span may need to be scrubbed.

For more details and data filtering instructions, see [Filtering Events](https://docs.sentry.io/platforms/python/configuration/filtering.md).

### [Examples](https://docs.sentry.io/platforms/python/data-management/sensitive-data.md#examples)

**Contextual information**

Instead of sending confidential information in plaintext, consider hashing it:

```python
sentry_sdk.set_tag("birthday", checksum_or_hash("08/12/1990"))
```

This will allow you to correlate it within internal systems if needed, but keep it confidential from Sentry.

**User details**

Your organization may determine that emails are not considered confidential, but if they are, consider instead sending your internal identifier:

```python
sentry_sdk.set_user({"id": user.id})

# or

sentry_sdk.set_user({"username": user.username})
```

Doing this will ensure you still benefit from user-impact related features.

**Logging integrations**

As a best practice you should always avoid logging confidential information. If you have legacy systems you need to work around, consider the following:

* Anonymize the confidential information within the log statements (for example, swap out email addresses -> for internal identifiers)
* Use `before_breadcrumb` to filter it out from breadcrumbs before it is attached
* Set the `level` parameter in the [logging integrations](https://docs.sentry.io/platforms/python/integrations.md#logging) you use to `None`.
