Privacy & compliance
Optional enrichment is off by default. Core analytics can start immediately or wait for consent depending on the site's compliance preset; identity capture, marketing fields, replay, fingerprinting, and behavioral trackers follow the consent and compliance settings you choose for that site.
Consent model
Every event the SDK emits is gated by a consent state stored in the _cs_consent first-party cookie + local-storage slot. The consent state is a tri-state per category:
| Category | Default | What it gates |
|---|---|---|
analytics | granted on opt-out presets (standard, ccpa); denied until consent is granted on opt-in presets (gdpr_strict, hipaa) | pageview, click, scroll, session tracking |
identity | denied until explicit grantConsent('identity') | HEM / phone / customer-id / social-id capture + transmission |
marketing | denied until explicit grantConsent('marketing') | click IDs (gclid, fbclid, etc.), UTM capture, replay, behavioral trackers |
Revoking consent clears every identity slot from storage + cookies, pauses the affected trackers, and emits a _consent_transition event so the server can scrub downstream state.
Optional Visitor Enrichment
ClickStream can run an optional visitor enrichment check for a site. This is off by default.
When a site owner turns it on from the Sites page optional enrichment card or Settings → Enrichment, the SDK loads the DataShopper (DataMoon) browser pixel directly and passes the active ClickStream visitor ID as the match key. When the processor finds a match, ClickStream receives the match tied to that visitor ID and can complete the person profile.
Use this only when your privacy notice and consent flow allow optional identity enrichment. Before enabling it, site admins must confirm that they have reviewed the applicable privacy and sub-processor disclosures. When this setting is off, ClickStream does not run the optional enrichment check.
This setting is separate from normal analytics and from server-side enrichment after a form fill or explicit identify() call. Basic pageview, click, scroll, Signals, and first-party tracking do not require optional enrichment.
Compliance presets
Set the preset at install time via data-compliance or the compliance config option:
<script
src="https://t.example.com/sdk.js"
data-key="cs_live_..."
data-compliance="gdpr_strict"
async
></script>
installClickstreamPixel({
apiKey,
endpoint,
compliance: 'gdpr_strict',
});
| Preset | Consent mode | Scrub level | Identity / fingerprint default | Encrypted-value retention |
|---|---|---|---|---|
standard | opt_out | standard | allowed when visitor identifies | 90 days, auto-purge on |
gdpr_strict | opt_in — denied until consent | aggressive | denied until identity consent | 180 days, auto-purge on |
ccpa | opt_out | standard | allowed; honors DNT + GPC | 90 days, auto-purge on |
hipaa | opt_in — denied until consent | aggressive | denied | 90 days, auto-purge on |
Retention in the table above applies to encrypted raw values stored per site (retentionDays, configurable). Separately: the Analytics Engine event stream has ~90-day platform retention, R2 export objects are removed on a 90-day cleanup cycle, and the audit log is retained 7 years.
The preset sets server-side defaults via ClientConfig.complianceProfile, which the collector uses to reject any event that carries fields the preset would have stripped — defense-in-depth against an old SDK bundle being cached on a visitor's device.
Consent sources — CMP detection + setConsent()
The SDK does not render a consent banner. On opt-in presets (gdpr_strict, hipaa) tracking is denied until consent is granted, from one of two sources:
- Your CMP, auto-detected. The SDK detects OneTrust, Cookiebot, and Osano, mirrors their consent decision, and subscribes to consent changes. You don't have to double-integrate.
- An explicit
setConsent()call. Any other CMP — or your own consent UI — can bridge its decision to the SDK:
window.cs?.getConsent(); // current consent state
await window.cs?.setConsent({ analytics: true, marketing: true, thirdParty: false });
await window.cs?.setConsent({ marketing: false });
With no CMP detected and no stored consent, opt-in presets collect nothing.
What's scrubbed at which level
standard scrub
- Query strings on
page.urlmatching common PII patterns (token=,email=,password=,access_token=,ssn=) are dropped. - Click element text longer than 128 characters is truncated.
- Form field values are NOT captured unless Universal Form-Fill Capture is explicitly enabled per site.
aggressive scrub
All standard rules plus:
document.referreris reduced to origin + path (query + fragment stripped).- Any field matching the SDK's broad PII heuristics (name, DOB, SSN, license, CC, health terms) is skipped even under form capture.
- Click text is truncated to 64 characters.
Raw PII — encrypted at rest, reveal-gated
When a site enables raw-value capture (email pre-encrypt on the server, form fills, IP addresses), values are AES-256-GCM encrypted with a unique key per site before they hit D1. Raw plaintext is never persisted anywhere.
Reveal requires all of:
- Dashboard operator with
decrypt:readpermission. - Password re-authentication within the last 5 minutes (
/decryptre-auth gate). - A recorded audit row (
audit_log) that captures operator id + IP + target visitor + timestamp + reason text. - Rate-limit allowance (10 reveals per operator per 15-minute window).
The audit log is append-only and retained 7 years; each site's Activity tab shows recent actions, and full history is available on request through support. Reveal access is controlled by the dashboard permission model, password re-authentication, and per-site encrypted storage; ClickStream operators do not bypass those gates.
Visitor rights — DSAR / export / deletion
Every dashboard site admin can:
- Export all data for a visitor — CSV + JSON bundle of every event, identity signal, form submission, and encrypted-field reveal associated with the
_cs_uidor any of its linked identifiers. - Delete a visitor — deletes the person record from primary stores (dashboard D1, identity graph, enrichment cache) immediately and propagates erasure to the collector; tombstones suppress the visitor from all dashboard reads. Immutable Analytics Engine rows and previously exported Parquet files cannot be selectively erased — they age out within 90 days — and the visitor is excluded from all future exports.
- Honor DNT / GPC — the SDK auto-respects
navigator.doNotTrack === '1'and Global Privacy Control (navigator.globalPrivacyControl === true) when compliance preset isccpa. CCPA already covers California's CPRA-specific GPC requirements; no separate preset is needed.
Use tracker.setConsent({ marketing: false }) (clears identity from the browser) + the dashboard delete action (purges server-side records) for a full visitor scrub.
Server-side compliance enforcement
The SDK already strips fields based on the compliance profile before transmission, but the collector strips them again as defense-in-depth. A cached old SDK bundle on a visitor's device can't smuggle fields past the collector — the server's ClientConfig.complianceProfile rules run on every event regardless of SDK version.
Regional considerations
- GDPR / UK GDPR — use
gdpr_strictfor EU-oriented defaults. Tracking is denied until consent is granted via your CMP or an explicitsetConsent()call. Processing under "legitimate interest" is deliberately NOT supported for marketing / identity categories. - CCPA / CPRA (California) — use
ccpa. The preset is opt-out — no consent gate on load; GPC and DNT signals are honored. Many CCPA sites pair it with a "Your Privacy Choices" link in their footer — your counsel decides what notice your site needs. CPRA's GPC enforcement is covered by the same preset — there is no separatecprapreset to configure. - HIPAA (US healthcare) — use
hipaafor HIPAA-aware settings: opt-in consent (denied until granted), aggressive scrubbing, and optional enrichment + customer-managed pixels hard-blocked. Not for PHI without a signed BAA — contact support before processing PHI. - PIPEDA (Canada) —
standard+ explicit consent flow on first visit meets PIPEDA baseline. - LGPD (Brazil) — use
gdpr_strict— LGPD's consent requirements are essentially a GDPR subset.
Data residency
- Primary storage — Cloudflare's global network (Analytics Engine + D1 + KV). Logical region assignment follows Cloudflare's data-at-rest residency program.
- EU-only residency — available only under a dedicated Enterprise deployment with a signed DPA and region-scoped Cloudflare configuration.
- US-only residency — available only under the same dedicated-deployment model.
- Cross-border transfers — identity enrichment is governed by the site's consent and compliance profile. Raw email and phone values are encrypted before storage, enrichment is disabled when the site configuration blocks it, and vendor-specific identity details are not exposed in customer-facing product surfaces.
DPA + sub-processor list
A Data Processing Agreement is available on request for Growth+ tiers through legal@clickstream.com; Scale+ customers can have a DPA appended to the MSA during provisioning. Current sub-processors:
- Cloudflare — ingestion, storage, compute, DNS.
- Stripe — billing + subscription metering. Does NOT receive any event data.
- DataShopper (DataMoon) — optional person-profile enrichment only when a site has enabled enrichment and the required consent posture is in place.
The sub-processor list is published at einstein.clickstream.com/legal/sub-processors — we update that page before onboarding any new sub-processor.
See also
- Security — encryption primitives + per-tenant isolation
- Optional enrichment — what gets hashed where
- Event schema — consent transitions —
_consent_transitionevent - First-party tracking (required) — tenant-scoped DNS + SSL provisioning