Consent records
The fields stored for every consent event, how explicit choices are distinguished from defaults, and what a signed receipt proves.
Every consent event your banner reports is written to a single row. This page lists what that row contains, because a record you cannot describe field by field is not evidence you can rely on.
What is stored
The banner posts to the consent endpoint, the server validates the payload and writes one row:
| Stored | Notes |
|---|---|
| Category decisions | necessary, analytics, marketing, preferences — booleans; necessary is always true |
| Consent ID | Opaque identifier generated in the browser and kept in the consent cookie |
| Client timestamp | The time the browser reported, after clamping (below) |
| Server timestamp | Written by the database on insert; this is the authoritative one |
| Banner and team | Resolved server-side from the public banner ID in the payload |
| Event type | One of consent_given, consent_changed, consent_default, accept_all, accept_necessary |
| Collection method | How the state was collected — see the table below |
| Default-state flag | True when the row was machine-written rather than chosen |
| Consent mode | optIn, optOut or notice, plus the mode actually resolved at runtime |
| Matched rule and geo source | Which regional rule matched, and how the location was determined |
| Country and region | Coarse location only, as provided by the edge |
| Domain | The domain the banner ran on |
| Referrer | Redacted to the banner's configured grouping level and truncated |
| Privacy signal | gpc, dnt or gpc_dnt when one was present, plus a flag recording that it shaped the state |
| US purpose choices | Sale/sharing, targeted advertising and sensitive data, when the visitor used the opt-out panel |
| Consent string | Populated only when the framework producing it is switched on; see the note at the end of this page |
Two ingestion paths, two sets of stored fields
Consent records reach the store through more than one endpoint, and they do not store the same fields. Read this before you describe CookieBeam's data handling in your own records of processing.
| Banner and preference centre | Versioned /api/v1/consent/log | |
|---|---|---|
| IP address | Not stored | Not stored |
| User agent | Not stored | Not stored |
| Page URL | Domain only | Not stored |
| Referrer | Truncated and redacted to the banner's grouping level | Not stored |
| Origin restricted to the banner's domains | Yes | No; the caller authenticates with an API key instead |
| Category, collection method, default-state, privacy-signal fields | Written | Not written |
| SDK platform and version | Not written | Written when the caller sends them, as the mobile SDKs do |
Neither path stores the visitor's IP address or user agent. The versioned endpoint is called server-to-server or from a native app, so the request's IP, user agent and referer describe the caller rather than the visitor, and it does not record them.
Records from the two paths are visibly different: only banner rows carry an event type and collection method, and only versioned-endpoint rows can carry an SDK platform.
Timestamp clamping
Browser clocks are wrong more often than people expect, and a skewed clock corrupts ordering. If the reported time is more than five minutes in the future or more than twenty-four hours in the past, the server replaces it with server time. The database's own insert timestamp is always authoritative regardless.
Explicit choices versus defaults
This is the distinction an auditor asks about first, so the schema carries it explicitly rather than leaving it to be inferred.
A row is machine-written when the runtime recorded a state the visitor never chose — an opt-out or notice model granting at page load, or an auto-grant in a region configured to hide the banner. Those rows are flagged, and the flag changes system behaviour:
- No webhook is dispatched. A machine-written default must never tell your downstream systems "this visitor consented".
- It is not billed as a consent log.
- US purpose choices are forced to null, server-side. Those values exist only after a visitor actively saves the opt-out panel, so a default row cannot carry them.
- It is not counted as a user action in banner metrics.
The collection method records the provenance:
| Value | Meaning |
|---|---|
banner | Chosen in the consent banner |
preference_center | Saved in the hosted preference centre — this is the value the preference-centre endpoint writes |
preferences | Declared by the runtime's own canonical state for a preference-centre change |
api | Set through the browser API by your own code |
default_optin | Opt-in default that grants nothing — an audit row, recorded only under experiments |
default_optout | Granted at load under an opt-out model |
default_notice | Granted at load under a notice model |
hidden_autogrant | Granted in a region configured not to show a banner |
Two of those values describe the same event. The preference-centre endpoint writes preference_center, while the runtime's own canonical consent state uses preferences for a preference-centre change. Match on both if you are classifying records by provenance.
If your reporting treats every stored row as "a visitor consented", it will overstate consent for any region you run in opt-out or notice mode. Filter on the default-state flag.
Preference-centre links
When an explicit consent row is written and carries a consent ID, the server issues an opaque preference-centre link and returns it to the banner. The link is a random token, valid for thirty days, that resolves to that consent record — so a visitor can revisit their choice without you exposing internal banner or team identifiers.
Signed receipts
A receipt turns a stored row into a portable, verifiable artifact. Requesting one requires both the consent log ID and the matching consent ID, compared in constant time; the request must also come from a domain authorized for that banner.
The receipt is a signed token whose payload contains the receipt and consent log IDs, the public banner ID, a subject hash, the four category decisions, the US purpose choices, the event type and collection method, the privacy signal, the default-state flag, the recorded timestamp, the origin the receipt was issued for, and an evidence level. The subject hash is a SHA-256 hash of the consent ID — the receipt therefore carries a pseudonymous reference, not an email address or a name.
The evidence level is verified when the consent request carried the valid per-banner beacon token from your published script, and unverified when it did not (scripts published before the token existed, or records written before the field existed). Treat verified as a weak signal: the token ships inside your public script, so anyone who reads that script can send it. Receipts issued by the versioned API carry no evidence level: that endpoint is authenticated with your secret API key. Receipts you download from the dashboard or a CSV export also carry no evidence level; check the record's beacon token status in the log itself.
Verification is a separate public endpoint, and current receipts require you to pass the origin you expect.
What verification proves:
- the token was signed with a CookieBeam signing key published at the verification-keys endpoint, and
- its contents have not been altered since signing, and
- it was issued for the origin you supplied.
What verification does not prove:
- that a human made the choice — the consent endpoint is public, so a receipt attests that CookieBeam received and stored this record, not who or what sent it,
- who the person behind the pseudonymous subject hash is,
- that the banner was configured correctly, or that your categories describe your actual tags,
- that the visitor saw, read, or understood the banner,
- anything about a row that was machine-written — a receipt for a default row faithfully reports that it was a default, and the flag is inside the signed payload for exactly that reason.
A receipt is proof that this record was received, what was recorded, and that the recording is intact. It is not proof that the recording was lawful.
A note on the consent string field
The record has a column for a transparency-and-consent-framework string. TCF support is built but not enabled in production — it is gated behind an environment flag that ships disabled by default, and the shipped configuration also has no vendor identifier set. The column therefore stays empty unless a deployment turns it on deliberately. Do not plan around it as an available feature, and do not describe your site as operating under that framework on the strength of this column existing.