How do I stop passwords, tokens and personal data from ending up in error reports?

Stop it at the source: configure the SDK so sensitive fields are never sent, using its data-collection options and beforeSend and breadcrumb hooks to drop or redact request bodies, headers, URLs, user fields and logged values. Add server-side scrubbing as a safety net, stop logging secrets, and rotate any credential that already leaked, since deleting an event does not un-expose it.

By the Bugsly team. Last updated . Markdown version

Why it happens

Error trackers work because the SDK attaches context to a crash: the request that triggered it, the user, the lines logged just before, sometimes the values of local variables. That same context is where secrets and personal data hide. A login endpoint fails and the form payload includes a password. A third-party API call fails and the URL contains an API key in the query string. A debug log line prints a session token, and the SDK records it as a breadcrumb.

Sentry's own documentation lists where sensitive data typically appears: stack locals (the Python, PHP and Node SDKs pick up variable values), breadcrumbs from log statements, database queries, HTTP query strings and fragments, user context controlled by sendDefaultPii, and transaction names or HTTP spans that contain raw URLs such as /users/1234/details. Request data in the Python integrations includes method, URL, headers, and form or JSON payloads, with raw bodies and multipart uploads excluded.

Defaults have also moved. Recent Sentry SDK documentation describes a newer data-collection option that replaces the single sendDefaultPii switch, and notes that opting in to its defaults is more permissive than sendDefaultPii set to false. Do not assume the default for your SDK version is conservative: check what your version collects, then restrict it deliberately and look at a real event before you trust it.

How to keep sensitive data out of error reports

  1. Inventory what your SDK sends by looking at a real event

    Trigger an error in staging with realistic input and read the full event JSON: request, headers, cookies, user, breadcrumbs, extra and local variables. Compare it to the leak surfaces in the table below. This step is more reliable than reading defaults from documentation, because defaults differ between SDKs and versions and your code adds its own context.

  2. Restrict collection with SDK options first

    Sentry's React and Python documentation describe the dataCollection (data_collection in Python) option for turning off categories such as user info, and sendDefaultPii as the older switch for user data; if you set both in Python, send_default_pii is ignored (Sentry docs, read 2026-11-13). The Python options also include include_local_variables, which is on by default and attaches local variable values, and max_request_body_size, which can be set to never. Turn off what you do not need rather than scrubbing it afterwards.

    sentry_sdk.init(
        dsn=...,
        include_local_variables=False,
        max_request_body_size="never",
        data_collection={"user_info": False},
    )
  3. Redact in beforeSend and beforeBreadcrumb

    Sentry's data-scrubbing guide recommends the beforeSend family of hooks to remove sensitive data before it leaves your environment: beforeSend for errors and messages, beforeSendSpan for spans, beforeSendLog for logs. Use beforeBreadcrumb to filter log-derived breadcrumbs before they attach, and strip or hash query strings that carry tokens. Prefer an allowlist for the fields you keep over a denylist of the ones you remember.

    Sentry.init({
      beforeSend(event) {
        if (event.user) delete event.user.email;
        if (event.request) { delete event.request.cookies; delete event.request.data; }
        return event;
      },
      beforeBreadcrumb(crumb) {
        if (crumb.category === "console") return null;
        return crumb;
      },
    });
  4. Identify users by an internal ID, not by email

    Sentry's guide suggests setUser with only an internal id or username if emails are considered confidential, which keeps user-impact counts working without personal details, and hashing contextual values before sending them as tags. Never put a name, email or phone number into a tag, which is searchable and widely visible to your team.

    Sentry.setUser({ id: user.id });
  5. Fix the logging, not just the report

    Sentry's documentation says you should avoid logging confidential information in the first place, because log lines become breadcrumbs. Redact secrets in your logger with a formatter or serializer, never log full request bodies or Authorization headers, and keep tokens out of URLs by sending them in a header. Fixing the log fixes your log store and the tracker.

  6. Add a server-side scrubber as a safety net, then rotate what leaked

    Scrubbing on the tracker side catches what your SDK rules miss, and Sentry's documentation distinguishes SDK-side scrubbing (data is not sent) from server-side scrubbing (data is not stored). Treat it as a backstop. If a password, token or key already reached any tracker or log, assume it is exposed: rotate it, then delete or expire the stored events according to your retention policy. Deleting the event does not make the credential safe again.

  7. Decide retention and who can see events

    Keep only as long as you need to debug. Limit the people who can open issues, because even scrubbed events can contain business data. Re-check after every SDK upgrade, since new integrations can add new fields.

Leak surface to control checklist
Leak surfaceExampleControl
Request bodiesPassword in a login form payloadDisable body capture, or redact in beforeSend
Headers and cookiesAuthorization, Cookie, session IDDrop headers and cookies in beforeSend; server-side scrub as backup
URLs and query strings?token=... or ?api_key=...Move secrets to headers; strip query strings in hooks; fix transaction names
User contextEmail, username, IP addressRestrict via dataCollection or sendDefaultPii; send an internal ID only
Breadcrumbs from logsA console.log that printed a tokenRemove the log; filter in beforeBreadcrumb
Console breadcrumbsDebug output captured automaticallyReturn null for console breadcrumbs in beforeBreadcrumb
Local variablesA function argument holding a secretTurn off local variable capture where the SDK has it
Tags and extra dataA tag set to an emailHash values or send internal identifiers only

Leak surfaces are from Sentry's scrubbing documentation (docs.sentry.io, read 2026-11-13); controls combine its recommendations with the steps above.

When to use Bugsly

Bugsly accepts the standard Sentry SDKs, so every SDK-side control above works unchanged. On ingest, before any event is stored, Bugsly also scrubs server-side: values of sensitive-looking keys (password, token, auth, secret, api key and similar), credit-card-looking numbers that pass the Luhn check, JWTs, Bearer tokens and well-known provider secret formats are replaced with [Filtered]. You can add your own field names per project, and IP scrubbing is optional. This is a safety net: it matches patterns and key names, so it cannot catch a secret stored under an innocent-looking key. It is not a substitute for not sending data.

If an AI assistant reads your errors over MCP, there is one more difference to know. The hosted MCP server omits user email, IP address, username and extra data from get_issue_events output and caps the output size. The local npm package @bugsly/mcp-server does not apply that redaction, size cap or rate limits, so use the hosted server unless your client cannot call a URL. Bugsly does not claim compliance certifications, so do not rely on a certification here.

When Bugsly is not the right answer

If a regulation or contract requires error data to stay on your own infrastructure, a hosted service is not the answer, and Bugsly cannot be self-hosted. In that case use a self-hosted tracker or your own log pipeline, with scrubbing applied before data leaves the process. If you are not allowed to send any user data to a third-party processor at all, note that Bugsly's AI analysis uses OpenAI as the processor, so confirm that is acceptable or avoid it for those projects.

Ask your AI assistant to do it

With the Bugsly MCP server connected (https://bugsly.dev/api/mcp; setup for ChatGPT, Claude, Cursor and Gemini CLI is on /mcp), paste this. The assistant reads first and reports back; you decide what happens next.

Assign to Bugsly: use list_projects to find my project, then list_issues and get_issue_events for the 5 newest unresolved issues. Check each event for anything that looks like a password, token, API key, email address or personal data in the request, URL, breadcrumbs or extra data, and report where it appears and which field name holds it. Do not resolve or ignore anything and do not repeat the secret values in your answer; show me what you found so I can approve the next step.

Frequently asked questions

Is server-side scrubbing enough on its own?

No. It matches key names and known patterns, so it can miss a secret under an unexpected key, and the data has already left your system. Use it as a backstop behind SDK-side controls.

I found a password in an old event. What now?

Rotate the credential first, because anyone who could view the event may have seen it. Then delete or expire the event according to your retention policy and fix the source so it is not sent again.

Does sendDefaultPii set to false remove everything sensitive?

No. It governs user-related data added by integrations. Query strings, breadcrumbs, logged values and local variables are separate surfaces that need their own controls.

Are console logs really sent with errors?

In the JavaScript SDK, previously logged statements can be attached as breadcrumbs, per Sentry's documentation. Avoid logging secrets, or filter console breadcrumbs with beforeBreadcrumb.

Sources

Related

Sentry is a trademark of its owner; Bugsly is not affiliated with or endorsed by Sentry. “Sentry-compatible” only means Bugsly accepts events sent by Sentry's open SDKs.