HIPAA-Compliant
Error Tracking
Sentry, Datadog and Rollbar are silently capturing PHI in your stack traces. Here's how to fix it — or replace them.
HIPAA-compliant error tracking is non-negotiable for production healthcare apps. But every time Sentry captures an unhandled exception, it packages up the stack trace, the request context, the session data and often the local variable values — then ships it to a third-party server. For most apps, that's fine. For HIPAA-covered applications, it can be an unauthorized disclosure of ePHI.
Why Error Trackers Are a HIPAA Risk
Modern error trackers are designed to capture as much context as possible to help you reproduce bugs. That's exactly the feature that creates the compliance problem. A single captured exception can contain:
/patients/12345/records?dob=1990-01-15
Authorization: Bearer eyJ...
{"diagnosis": "F32.1", "mrn": "MRN-88421"}
$patient_email = "alice@example.com"
UNIQUE constraint failed: patients.ssn
user_id: 882, role: patient, ward: oncology
This is an unauthorized disclosure of ePHI
Under HIPAA's Security Rule (45 CFR §164.312), sending ePHI to a third-party error tracking service without a Business Associate Agreement constitutes an unauthorized disclosure — regardless of whether you intended to include PHI in the error event. Intent is not a defense.
Which Error Trackers Offer BAAs?
A Business Associate Agreement is the legal minimum for using a managed error tracking service with PHI-containing applications. Not all vendors offer one:
| Service | BAA Available? | Plan Required | Notes |
|---|---|---|---|
| Sentry (cloud) | ✓ Yes | Business or Enterprise | Request via support. Also offers self-hosted OSS option. |
| Sentry OSS (self-hosted) | ✓ Not needed | Free | All data stays on your servers. Strongest HIPAA posture. |
| Datadog | ✓ Yes | Enterprise / negotiated | BAA covers APM and log management products. |
| New Relic | ✓ Yes | Enterprise | Full observability platform with BAA for enterprise customers. |
| Rollbar | ✗ No public BAA | — | No published BAA. Do not use for PHI-containing apps without scrubbing all data client-side first. |
| Bugsnag | ✗ No public BAA | — | No published BAA. Same guidance as Rollbar. |
| Grafana / Loki / Tempo | ✓ Self-hosted | Free (self-hosted) | Open-source stack. All data on your infrastructure. |
How to Scrub PHI from Sentry
Even with a BAA, best practice is to scrub PHI before it leaves your application. A BAA is a legal safeguard — scrubbing is technical prevention. Do both.
Python — before_send hook
The before_send hook runs on every event before it is transmitted. Return None to drop the event entirely, or modify the event dict to remove sensitive fields:
import sentry_sdk
import re
def scrub_phi(event, hint):
"""Remove PHI from Sentry events before sending."""
# Drop events from PHI-heavy endpoints entirely
request = event.get("request", {})
url = request.get("url", "")
if "/patients/" in url or "/medical-records/" in url:
# Scrub the URL — keep the path structure but remove IDs
request["url"] = re.sub(r"/patients/\d+", "/patients/[REDACTED]", url)
# Scrub request body
if "data" in request:
request["data"] = "[SCRUBBED]"
# Scrub query string
if "query_string" in request:
request["query_string"] = "[SCRUBBED]"
# Scrub user context
if "user" in event:
user = event["user"]
if "email" in user:
user["email"] = "[REDACTED]"
if "username" in user:
user.pop("username", None)
# Scrub extra context
event.pop("extra", None)
return event
sentry_sdk.init(
dsn="https://your-dsn@sentry.io/project-id",
before_send=scrub_phi,
# Also configure built-in scrubbing
send_default_pii=False, # Critical — disables auto PII collection
)
JavaScript / Node.js — beforeSend hook
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: "https://your-dsn@sentry.io/project-id",
sendDefaultPii: false, // Never send default PII
beforeSend(event) {
// Scrub request body
if (event.request) {
event.request.data = "[SCRUBBED]";
event.request.query_string = "[SCRUBBED]";
event.request.cookies = "[SCRUBBED]";
// Redact PHI patterns from URL
if (event.request.url) {
event.request.url = event.request.url
.replace(/\/patients\/\d+/g, "/patients/[ID]")
.replace(/mrn=[^&]+/gi, "mrn=[REDACTED]")
.replace(/dob=[^&]+/gi, "dob=[REDACTED]");
}
}
// Remove user email
if (event.user) {
delete event.user.email;
delete event.user.username;
delete event.user.ip_address;
}
// Remove all extra context (may contain session data)
delete event.extra;
return event;
},
});
Sentry Dashboard — Data Scrubbing Settings
In addition to code-level scrubbing, configure Sentry's server-side data scrubbing as a second layer:
How to Scrub PHI from Datadog
Datadog's APM and Log Management products support obfuscation rules. For error tracking specifically, configure the tracer's obfuscation settings:
# Python (dd-trace)
from ddtrace import config, tracer
# Obfuscate query strings matching PHI patterns
config.trace_http_header_tags = {} # Don't capture headers
# In ddconfig.yaml or environment variables:
# DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP=mrn=[^&]*|dob=[^&]*|ssn=[^&]*
# For logs, configure log scrubbing rules in datadog.yaml:
# logs_config:
# processing_rules:
# - type: mask_sequences
# name: mask_mrn
# replace_placeholder: "[MRN_REDACTED]"
# pattern: MRN-\d+
// Node.js (dd-trace)
const tracer = require('dd-trace').init({
// Obfuscate sensitive query parameters
queryStringObfuscation: /mrn=[^&]*/gi,
// Don't capture request bodies on these routes
blocklist: ['/patients', '/medical-records', '/prescriptions'],
});
The Nuclear Option — Self-Hosted Sentry OSS
If you need the cleanest possible HIPAA posture and have devops capacity, self-hosted Sentry eliminates the third-party risk entirely. All error data stays on infrastructure you control — no BAA required because you're not sending data to a third party at all.
# Install via Docker Compose (official method)
git clone https://github.com/getsentry/self-hosted.git
cd self-hosted
./install.sh
# Or via Helm on Kubernetes
helm repo add sentry https://sentry-kubernetes.github.io/charts
helm install sentry sentry/sentry \
--set user.email=admin@yourcompany.com \
--set user.password=yourpassword
Self-hosted Sentry gives you the same UI and SDK compatibility as Sentry cloud. The trade-off is infrastructure management — you're responsible for backups, updates and availability.
HIPAA Error Tracking Compliance Checklist
Test with synthetic PHI before going live
After configuring scrubbing, trigger test errors using fake patient data (fabricated names, MRNs and diagnosis codes) and verify the captured events contain no real-looking PHI. Check request bodies, URLs, stack frame locals and user context fields.
Before Sharing Error Logs — Sanitize First
Even with error tracking properly configured, you may sometimes need to share raw logs or stack traces for debugging — with a colleague, a vendor or an AI assistant. Always sanitize first.
Sanitize Logs Before Sharing
Strip emails, IPs, API keys and PHI patterns from logs in seconds. 100% client-side — nothing uploaded.
Open Log Sanitizer — Free →FAQ
Does Sentry offer a HIPAA BAA? +
Yes. Sentry offers a BAA on Business and Enterprise plans. Contact their support team to request it. Alternatively, self-hosted Sentry OSS requires no BAA since all data remains on your own infrastructure.
Can PHI end up in error tracking events? +
Very easily. Stack frames capture local variable values at crash points. Request context includes the full URL (which may contain patient IDs), query parameters, and headers. Session context includes user identity. Any of these can contain PHI without the developer explicitly including it.
What is the safest error tracking setup for a HIPAA app? +
Self-hosted Sentry OSS — all data stays on infrastructure you control, no third-party BAA required. For managed services, Sentry Business or Datadog with a signed BAA and a before_send scrubbing hook configured is the next best option.
Is a BAA enough, or do I also need to scrub PHI? +
A BAA is the legal minimum — it creates a contractual obligation for the vendor to protect PHI. But it doesn't prevent PHI from being captured and stored. Technical scrubbing is the preventive layer. Best practice is both: BAA for legal coverage, scrubbing to minimize the PHI that ever reaches the vendor's servers.