Guides

Consent log: the tamper-evident hash-chained ledger

AdminUpdated Sep 15, 2026

Consent log: the tamper-evident hash-chained ledger

What it's for

Every time your banner captures a decision — accept, reject, or a granular "save preferences" click — Cookie Munch writes one durable record to the consent log. This is the system of record: the thing you point to when a regulator, a customer's legal team, or your own DPO asks "can you prove this visitor consented, and to what, at what time?"

The log is per-site (keyed by your property's cbid), append-only, and hash-chained: every record's hash is derived in part from the previous record's hash, so altering or deleting a historical entry breaks the chain from that point forward. You aren't just storing consent events — you're storing a ledger whose integrity you can independently check.

What a record contains

Each entry captures:

Field

Description

stamp

The unique consent-receipt ID for this decision. This is the key you use everywhere else — to fetch a signed receipt, to export a subject's data, or to erase it.

receivedAt

The server-side timestamp the decision was ingested (separate from utc, the client-reported decision time).

region

The visitor's detected region at decision time (e.g. de, us-ca), used for geo/GPC reporting and receipt jurisdiction.

method

explicit (the visitor clicked something) or implied (a passive/default outcome).

choices

The granted booleans: preferences, statistics, marketing. necessary is never a toggle — it's always granted, since the site can't function without it, and shows up in every receipt as an implied purpose.

anonIp

A truncated, anonymized form of the visitor's IP. The raw address is never stored.

url

The page the decision was made on.

If your banner also collects named purposes (beyond the four built-in categories) or is wired to a RoPA entry, those are captured too and surface later in a signed receipt (see Audit export & receipts).

Where you'll find it in the dashboard

There's no single "browse every row" grid in the dashboard today — the log is a backend ledger, queried through the API rather than paged through visually. In practice you'll interact with it two ways:

  1. Indirectly, via Privacy tools. Dashboard → Privacy → DSAR is where the stamp actually gets used day to day: when you fulfill an access or erasure request, you paste in the site's cbid and the subject's stamp to export or crypto-erase their record (see DSAR requests). That stamp is exactly the primary key of a consent-log entry.

  2. Directly, via the API. Query recent decisions for a site:

    GET /api/v1/:cbid/consent/log?from=&to=&limit=

    Results are newest-first; limit defaults to 200 and caps at 1000. Optional from/to (epoch ms) bound the window. This is the same data source behind the CSV export and the DSAR export/erase tools, so anything you can do to a record from Privacy → DSAR, you can also script against this endpoint directly.

To call it yourself, go to Dashboard → Developers → API keys and issue a key with the Consent scope (consent:read for log/export/verify, consent:write if you're also posting server-side decisions). Consent-log reads require authentication in multi-tenant deployments — the ledger is never publicly readable, unlike the cookie-declaration feed.

Verifying chain integrity

Because each record's hash incorporates the previous one, you can check at any time whether the stored chain has been tampered with or corrupted:

GET /api/v1/:cbid/consent/verify

This returns { "valid": true | false }. A false result isn't a data quality nit — it means the ledger itself has been altered outside the normal append path, and should be treated as an operational/security incident worth investigating immediately.

Two additional guarantees sit under the hood, worth knowing about even though they're invisible day to day:

  • If your server has CONSENT_SIGNING_KEY configured, every appended record is HMAC-signed over its hash — the chain becomes tamper-proof, not just tamper-evident: a forged record can be mathematically rejected, not just detected after the fact.

  • Personal fields (userAgent, page url) are encrypted per-subject, and the hash is computed over the ciphertext. That's what makes crypto-erasure (used by DSAR deletion requests) safe: erasing a subject's encrypted fields never breaks the hash chain for records around it.

What the data means

method: implied vs explicit tells you whether a decision reflects an active click or a passive default (useful for auditing "implied consent" regions). The choices object is your ground truth for what a specific person actually agreed to — this is what Analytics aggregates into opt-in rates, and what a signed receipt formats into a human-readable purpose breakdown.

Export and compliance value

The consent log is the foundation everything else in "Records" is built on:

  • CSV export and signed receipts are read-only views over this same ledger — see Audit export & receipts.

  • DSAR access/erasure operates by stamp, looking a subject up directly in this log — see DSAR requests.

  • Analytics is the aggregated, anonymized rollup of these same decisions — see Analytics & A/B testing.

If you only remember one thing: the stamp is the thread that connects a single visitor's decision to every downstream tool — receipts, exports, and DSAR fulfillment all key off it.

See also: Audit export & receipts · DSAR requests · Preference center

Was this page helpful?