Developer Implementation Guide

Table of Content

Table of Content

Table of Content

Store and track consent effectively

Capture consent (and opt-out choices) in a way that’s granular, provable, and easy to enforce. Version the text people agree to, log every change as an append-only event, and propagate decisions to vendors in near-real time.

Capture consent (and opt-out choices) in a way that’s granular, provable, and easy to enforce. Version the text people agree to, log every change as an append-only event, and propagate decisions to vendors in near-real time.

Principles and scope

  • Use consent only when it’s the right lawful basis; don’t ask for consent if you rely on contract or legitimate interests.

  • Keep it granular by purpose (e.g., analytics, email marketing, personalized ads) and channel (email, SMS, push).

  • Make it easy to withdraw at any time; withdrawals must be as easy as giving consent.

  • Treat CPRA opt-outs (sale/share, targeted advertising) as first-class preferences alongside GDPR consent.

  • Respect browser signals like GPC (Global Privacy Control) as an opt-out for sale/share and targeted ads.

Data model (append-only)

-- What purposes exist and their current policy text/version
CREATE TABLE consent_purposes (
  id text PRIMARY KEY,            -- e.g., "analytics", "email_marketing", "ads_personalized", "sale_share"
  title text NOT NULL,
  policy_version text NOT NULL,   -- "v2025-09-01"
  policy_text_hash text NOT NULL  -- sha256 of the exact UI copy shown
);

-- Events, never overwrite: one row per give/withdraw/update
CREATE TABLE consent_events (
  id uuid PRIMARY KEY,
  subject_id text NOT NULL,       -- DSID pseudonym or user_id
  purpose_id text NOT NULL REFERENCES consent_purposes(id),
  action text NOT NULL CHECK (action IN ('given','withdrawn','opt_out','opt_in','limit_use')),
  lawful_basis text,              -- 'consent','legitimate_interests','contract' (for record)
  policy_version text NOT NULL,
  source text NOT NULL,           -- 'web','ios','android','api','import'
  locale text,                    -- 'en-US'
  gpc boolean DEFAULT false,
  gpp_string text,                -- optional IAB GPP string
  tcf_string text,                -- optional IAB TCF string
  ip_net text,                    -- truncated IP for context (e.g., /24)
  ua_hash text,                   -- hash of User-Agent, not raw
  created_at timestamptz DEFAULT now()
);

-- Current effective state (materialized view or table you rebuild)
CREATE TABLE consent_state (
  subject_id text,
  purpose_id text,
  status text CHECK (status IN ('granted','denied','opted_out','limited')),
  updated_at timestamptz,
  PRIMARY KEY (subject_id, purpose_id)
);

API surface

POST /consents
Content-Type: application/json
{
  "subject_id": "dsid_7b8c...",
  "purpose_id": "analytics",
  "action": "given",
  "policy_version": "v2025-09-01",
  "idempotency_key": "6b2b9a6a-..."
}

PATCH /consents/withdraw
{ "subject_id":"dsid_7b8c...", "purpose_id":"email_marketing" }

GET /consents/state?subject_id=dsid_7b8c

Front-end capture patterns

  • Show purpose-grouped toggles with clear “On/Off” copies, links to policy text, and last-updated date.

  • Disable non-essential cookies and SDKs until consent is given for that purpose.

  • Merge anonymous/browser consent to the account on login (subject linking), with a conflict-resolution rule that favors the most restrictive choice.

// Respect GPC in web apps
const gpc = navigator.globalPrivacyControl === true;
if (gpc) recordOptOut('sale_share'); // store consent_event with gpc=true

// Gate non-essential scripts until consent:
if (hasConsent('analytics')) loadAnalytics();

Enforcement hooks

  • Check consent_state at runtime before firing SDKs, setting cookies, or exporting data to vendors.

  • For outbound events, attach purpose flags so your pipeline can drop disallowed traffic.

function sendAnalytics(evt) {
  if (!hasConsent('analytics')) return;
  analytics.track(evt);
}

Vendor propagation

  • Maintain per-vendor adapters for subscribe/unsubscribe and privacy preferences.

  • Send updates within minutes; store vendor receipts and last sync time.

{ "vendor":"mail_service_x", "purpose":"email_marketing",
  "subject_id":"dsid_7b8c...", "action":"withdrawn",
  "receipt_id":"abc123", "synced_at":"2025-09-03T22:40:00Z" }
  • When purpose wording or usage changes, bump policy_version and require re-consent only for affected purposes.

  • Keep the policy_text_hash to prove exactly what was shown.

Regional logic

  • Detect region to set defaults (e.g., opt-out by default for sale/share in CPRA contexts).

  • Honor “Limit Use of Sensitive PI” with a distinct purpose_id and stricter defaults.

Emails and messaging

  • Map unsubscribe links to purpose-specific withdrawals (not a blanket “all”). Include a one-click endpoint that doesn’t require login.

Audit and reporting

  • Produce a consent receipt per subject with the latest state and event history. Include purpose, policy version, action, source, and timestamps.

  • Alert on anomalies: sudden mass withdrawals, adapter failures, or unsynced vendors.

{
  "subject_id": "dsid_7b8c...",
  "as_of": "2025-09-03T22:44:00Z",
  "purposes": [
    {"id":"analytics","status":"granted","policy_version":"v2025-09-01","last_event":"2025-08-20T14:12:00Z"},
    {"id":"sale_share","status":"opted_out","gpc":true,"last_event":"2025-09-03T10:00:00Z"}
  ]
}

Edge cases

  • Minors: require verified parental consent where applicable; store age-gating evidence without keeping full DOB if you can avoid it.

  • Merged accounts: union event histories; compute state with restrictive precedence.

  • Offboarding: on account deletion, keep minimal consent receipts only if needed to prove compliance, with tight retention.

  • Purpose- and channel-level granularity with clear UI and easy withdrawal

  • Append-only consent_events plus computed consent_state for fast checks

  • Region-aware defaults; enforce GPC as opt-out for sale/share and targeted ads

  • Block non-essential cookies/SDKs until consent; merge anonymous → account safely

  • Vendor adapters with receipts and near-real-time propagation

  • Policy text versioning and hashes to prove what was shown

  • Consent receipts and alerts for adapter/sync failures

Conclusion

Granular, versioned, and auditable consent turns promises into enforceable controls. By logging immutable events, computing fast runtime state, honoring signals like GPC, and syncing decisions to vendors, you meet GDPR and CPRA expectations while keeping your product behavior aligned with each person’s choices.