GDPR and error tracking: the parts your DPO hasn't asked about yet

URL fragments, request bodies, IP addresses, breadcrumbs — the four places PII enters error data that even careful teams miss.

·
privacygdprcompliance

You've spent weeks configuring beforeSend to scrub the email field from your API requests. Your DPO is happy. Then a user clicks a "Reset Password" link, the application throws a 404, and your error tracker dutifully captures the entire URL—including the plaintext token in the fragment (#token=eyJhbGc...). Because fragments never reach the server, your backend logs are spotless. But your error tracking dashboard is now a GDPR liability sitting in plain sight, and nobody asked about it because it doesn't look like "PII."

This is the gap between compliance theater and actual data protection. Most teams treat GDPR in error tracking as a search-and-replace job: find the obvious identifiers, scrub them, done. But the regulation defines personal data far more broadly than "name and email," and the worst leaks live in the structural plumbing of your SDK—the fragments, breadcrumbs, request bodies, and metadata your DPO's questionnaire never thought to ask about.

The Compliance Mirage: Why "Scrubbing Emails" Isn't Enough

GDPR Article 4 defines personal data as any information relating to an identified or identifiable natural person. That "identifiable" clause is doing enormous work. It means a value doesn't have to be a name to be PII—it just has to be capable of singling someone out, alone or in combination with other data you hold.

Data at rest vs. contextual data

The PII your DPO worries about is "data at rest"—the labeled fields in your database. The PII that actually leaks into error trackers is contextual: the runtime state your SDK scoops up automatically to make debugging easier. Here's the mental model:

  • Obvious PII: name, email, phone, postal address. Everyone scrubs these.
  • Contextual PII: IP address, session hashes, user IDs, breadcrumb trails, page titles, URL fragments. Almost nobody scrubs these, and every one of them can identify a person.

Why your DPO's checklist misses the technical "how"

A DPO questionnaire asks "do you store user emails?" It does not ask "does your frontend SDK serialize window.location.hash into the event payload?" The checklist operates at the policy layer; the leaks happen at the SDK-configuration layer. Bridging that gap is an engineering responsibility, not a legal one—and it's the same broad "identifiability" problem that makes HIPAA error tracking so unforgiving for healthcare apps.

The URL Fragment Trap: Client-Side Stealth PII

Single-page apps lean heavily on the URL fragment (everything after the #) for routing and state. The defining property of the fragment is that browsers never transmit it to the server. That's great for security—and a disaster for error tracking, because your frontend SDK absolutely does capture it.

Why fragments are the dark matter of PII

Server logs are clean because the fragment was never sent. So when a security review checks the backend, it finds nothing. Meanwhile the client SDK reads window.location.href—fragment included—and ships it inside event.request.url. Magic links, OAuth callbacks, and password-reset flows routinely stash tokens and even email addresses in the fragment. That data is invisible to everyone except the error tracker, where it sits indefinitely.

Stripping it in beforeSend

Sentry.init({
  dsn: process.env.GLITCHREPLAY_DSN,
  beforeSend(event) {
    if (event.request?.url) {
      // Drop the fragment entirely, then strip token-like query params.
      let url = event.request.url.split("#")[0];
      url = url.replace(
        /([?&](?:token|auth|session|key|jwt)=)[^&]+/gi,
        "$1[redacted]"
      );
      event.request.url = url;
    }
    return event;
  },
});

Breadcrumbs: The Forensic Trail of User Behavior

Breadcrumbs reconstruct the story leading up to an error—the clicks, navigations, and state changes. They're invaluable for debugging and quietly dangerous for privacy, because the "story" is literally a record of one person's behavior.

The last-known-state problem

Teams that attach their Redux or Vuex store to breadcrumbs (a common "capture everything" pattern) end up serializing the entire client-side application state into every error. If that store holds the current user's profile, cart, or form-in-progress, you've just logged a complete PII snapshot as "debugging context."

The title and alt-text leak

Automated UI breadcrumbs record the element a user interacted with, often including its text, title, or aria-label. Consider a patient navigating a portal where each page title reads "Lab Results — Jane Doe (MRN A8842)". Every click breadcrumb now carries that title verbatim. Nobody wrote code to log a name; the framework did it for free. Use beforeBreadcrumb to filter or redact breadcrumb data the same way you filter events.

Request Bodies and the "JSON.stringify" Habit

Attaching the full request payload to an error feels like a gift to your future debugging self. It is also one of the densest PII sources in the whole pipeline.

The danger of nested objects

Scrubbing rules that match top-level keys miss data buried three levels deep. order.billing_address.street survives a scrub that only looks for a top-level address key. Arrays of objects are worse—a line_items array where each entry carries a recipient_email defeats most naive key matchers. Recursive scrubbing is the only reliable approach.

Multipart and binary blobs

When an error fires during a multipart/form-data upload, an over-eager SDK can capture the file contents—a scanned ID, a medical document, a signed contract. Here's a short list of keys worth scrubbing globally before they ever leave the client: ssn, dob, billing_address, password, token, card_number, cvv, phone.

IP Addresses: The Metadata Your SDK Collects by Default

Under GDPR, an IP address is personal data. This was settled by the Court of Justice of the EU, and reinforced by the 2022 Austrian and French data-protection-authority rulings that found sending EU visitors' IPs to US analytics services unlawful without additional safeguards. Yet nearly every error SDK records the client IP automatically, inferred from request headers.

Cloudflare, proxies, and X-Forwarded-For

When your app sits behind Cloudflare or any reverse proxy, the real client IP arrives in X-Forwarded-For or CF-Connecting-IP. SDKs and ingest servers parse these to attribute events to a user. If you don't explicitly disable or anonymize that, you're collecting PII on every single event by default.

Mask or delete?

You have two compliant options. Anonymize—truncate the last octet (203.0.113.0) to preserve coarse geography for debugging while breaking individual identification. Or delete—drop the IP entirely if you don't need it. The right choice depends on whether geographic context ever helps you debug; for most apps, deletion is the safer default.

Session Replay: The New Frontier of PII Risk

Session replay records the DOM, which makes it the single highest-risk surface for PII leakage. A replay can capture everything a user typed and saw.

Why mask-all should be the default

The compliant posture is to mask all text and inputs by default, then selectively unmask the few elements you've verified are safe. The opposite—record everything, mask the sensitive bits—fails open: any field a developer forgets to flag leaks in full. Default to closed.

The CSS-in-JS attribute leak

Replay tools mask visible text, but data hidden in attributes can slip through. A component that stashes a user's email in a data-user attribute, or a tooltip that renders a phone number into a title, won't be caught by text masking alone. Audit your DOM for PII living in attributes, not just in rendered text.

Building a Privacy-First Error Pipeline

The fix is to stop treating scrubbing as a reactive patch and start treating privacy as a pipeline property.

A global scrubbing utility

Centralize your scrubbing logic in one wrapper around your SDK initialization, applied to events, breadcrumbs, and request data alike. One recursive function, one allowlist, one place to audit. Scattering ad-hoc redaction across call sites guarantees gaps. And the performance cost is negligible—recursive scrubbing of a typical event payload adds well under a millisecond, far less than the network round-trip it precedes.

Scrub-at-source proxies

The strongest architecture scrubs at the edge, before data is ever persisted. Sentry calls this Relay; GlitchReplay runs PII scrubbing on Cloudflare Workers at ingest, so redaction happens at the network boundary rather than after storage. You can read the rule model in our PII documentation and test rules against your own payloads with the PII scrubbing tool.

Why flat-rate pricing helps compliance

Per-event pricing creates a perverse incentive: teams drop data to save money, which means they also stop scrubbing the data they didn't bother to ingest—until one day they need it. Flat-rate pricing removes the cost pressure entirely, so you can capture completely and scrub deliberately. GlitchReplay is Sentry-SDK compatible, applies edge-side scrubbing by default, and bills a flat rate. Our data-processing terms live at /dpa and our privacy posture at /privacy.

GDPR compliance in error tracking isn't a one-time scrub of the email field—it's a continuous discipline applied to the four blind spots your DPO never asked about: URL fragments, breadcrumbs, request bodies, and IP metadata. Close those, centralize your scrubbing, and push redaction to the edge. That's the difference between a dashboard your auditors trust and a liability you didn't know you were storing.

Stop watching your error bill spike.

GlitchReplay is Sentry-SDK compatible, includes session replay and security signals, and never charges per event. Free to start, five minutes to first event.