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

MethodHeaderWhere
API keyX-Api-Key: <key>Server-side only. Tenant-wide write access.
Bearer JWTAuthorization: Bearer <jwt>Browser / short-lived. Tenant from tenant_id claim.
Never ship an API key to the browser

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 tenantId to 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 ***).

On by default
Every SDK ships with payload redaction enabled(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

PatternBecomes
Email addressesj***e@example.com (first/last char kept)
Credit-card numbers****-****-****-1234 (last 4 kept)
Phone numbers415****6789
US SSN-like values***-**-****
JWTs (eyJ…header.payload.sig)eyJhbGciOi...***
API keys / bearer tokens (key: value)abcd*** (first 4 kept)
Passwords embedded in URLsuser:********@host
IBANsDE89***6789

Keys always replaced with ***

passwordsecrettokenapi_keyauthorizationcookiessncredit_card

Any 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.

Practices that matter more than masking
  • Send path or route instead 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 + pathname for url/referrer — never query strings or hash fragments.
  • element_clicked never 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 / route over full URLs in server-side payloads.
  • Use onBeforeEnqueue / OnBeforeEnqueue to drop or transform fields you never want to leave your boundary.
  • Keep a stable idempotencyKey per logical event so retries can't double-count.
Defense in depth

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.