Security & data masking
Authentication, sensitive-data redaction, and ingestion best practices.
ChurnWarn is built to do its job — score churn risk — without becoming a second copy of your customers' PII. This page covers how to authenticate safely and how the SDKs keep sensitive data out of your event stream.
Authentication
| Method | Header | Where |
|---|---|---|
| API key | X-Api-Key: <key> | Server-side only. Tenant-wide write access. |
| Bearer JWT | Authorization: Bearer <jwt> | Browser / short-lived. Tenant from tenant_id claim. |
An X-Api-Key can write events for your entire tenant. In client
code use a short-lived Bearer token, and restrict allowed origins in the API's
CORS configuration.
- Rotate keys from Settings → API keys; revoke any key that may have leaked.
- CORS: the browser SDK calls
POST /api/events, so your page origin must be on the API allow-list. A blocked request shows as a CORS error in the console. - Tenant scoping: omit
tenantIdto use the credential's tenant. Only pass it to target another tenant you're explicitly authorized for.
Sensitive-data masking
Every SDK redacts payloads in-process, before an event is queued — unmasked
data never leaves your application. Masking is on by default, bounded, and never
throws (it falls back to a safe ***).
redact_payload / redactPayload). Sensitive values are masked in-process before an event is queued, so unmasked data never leaves your application. Masking is bounded, never throws, and falls back to a safe *** on any error.Values detected and masked inside strings
| Pattern | Becomes |
|---|---|
| Email addresses | j***e@example.com (first/last char kept) |
| Credit-card numbers | ****-****-****-1234 (last 4 kept) |
| Phone numbers | 415****6789 |
| US SSN-like values | ***-**-**** |
| JWTs (eyJ…header.payload.sig) | eyJhbGciOi...*** |
| API keys / bearer tokens (key: value) | abcd*** (first 4 kept) |
| Passwords embedded in URLs | user:********@host |
| IBANs | DE89***6789 |
Keys always replaced with ***
passwordsecrettokenapi_keyauthorizationcookiessncredit_cardAny key containing one of these words has its value redacted. Keys named url / referrer (or ending in url) keep only their path — query strings and hash fragments are stripped.
- Send
pathorrouteinstead of full URLs in server-side payloads. - Never use an email or username as
external_account_id— use a stable non-PII id. - Masking is a safety net, not a license to send secrets. Keep payloads minimal.
What ChurnWarn intentionally does not collect
- The browser SDK sends only
origin + pathnameforurl/referrer— never query strings or hash fragments. element_clickednever captures visible button/link text; labels come from stable attributes and are themselves masked.- There is no automatic form-field value capture.
Recommendations
- Use a stable, non-PII value for
externalAccountId(an internal id, not an email). It appears throughout the product UI. - Keep payloads minimal — send the few fields a metric needs, not whole objects. Redaction is a safety net, not a reason to send secrets.
- Prefer
path/routeover full URLs in server-side payloads. - Use
onBeforeEnqueue/OnBeforeEnqueueto drop or transform fields you never want to leave your boundary. - Keep a stable
idempotencyKeyper logical event so retries can't double-count.
Masking protects against accidental leakage of common patterns. It does not replace your own review of what each event carries. Treat the payload schema as part of your data-handling surface and keep it lean.