Skip to content

Consent records

Read, export and retain signed consent decisions and their linked history.

Consent stores each visitor decision as a signed server record. You can review statistics, export records as CSV, or retrieve a decision chain using the record id from a visitor’s cookie.

Records are retained for 1095 days. Their contents and retention can support your records of consent, but do not by themselves establish that you meet a particular legal obligation.

What a record contains

Field
Meaning
recordId
Identifier of this decision
necessary, preferences, statistics, marketing
Category flags
method
explicit, implied or withdrawal
ver
Decision format version
utc
Server timestamp of the decision
region
Two-letter country code, or empty
page_url
Page origin and path
stamp
Cryptographic signature over the canonical fields
providers_rev
Provider-set versions disclosed for the decision
replaces_id
Previous record in the decision chain, if any

Records contain no name, email, IP address, visitor id, user agent or device fingerprint.

The stamp

Each product has a signing key. Consent uses it to compute a truncated HMAC-SHA-256 over a canonical set of fields. The stamp can establish whether those fields have changed since signing; it does not attest to fields outside that set.

The page URL keeps no query string

The banner removes the query string and fragment before sending page_url, and the server strips them again before storage. Only origin and path remain, avoiding query parameters such as ?email= or ?token= in the record.

necessary is always true

The API rejects necessary: false, and the database enforces the same rule. The banner’s necessary category cannot be declined.

Withdrawal is a record, not a deletion

Withdrawing creates a record with method: withdrawal and replaces_id pointing to the previous choice. Other choice changes also link to the record they replace, so the chain preserves the decision history.

An unknown replaces_id, or one belonging to another product, is stored as empty. Links cannot cross product boundaries.

Statistics

Use consent_stats_get or the app’s reports tab to read decisions over a window. The response includes:

  • total: the number of records.
  • accept_all_pct, deny_all_pct and custom_pct: the percentage in each choice group.
  • by_category: percentages for each optional category.
  • range.from and range.to: the exact bounds used by the query.

Supply the window as Nd, such as 30d or 90d. Invalid formats return an error. The server’s default window is 30 days and its default maximum is 365 days.

The optional flags determine the group: all three true means accept_all, all false means deny_all, and a mixture means custom. A withdrawal with all optional flags false therefore counts in deny_all.

Percentages are rounded independently to whole numbers and can sum to 99, 100 or 101. With no records, total and all percentages are zero. Use the returned range.from and range.to for an export that matches the statistics window.

consent_dashboard_stats_get provides the smaller summary used when the dashboard opens.

Recent decisions

consent_dashboard_decisions_list returns up to ten recent decisions, newest first. The server labels each row withdrawal when that is its method; otherwise it uses accept, deny or custom from the flags. The app and MCP receive the same labels.

Export

Both export paths require Admin access. They read the same records:

Path
Result
GET /consent/dashboard/export
Streaming CSV, using a server-side cursor rather than buffering the full export
consent_records_export
Inline CSV: 1000 rows by default, at most 10000

When more records match than the inline limit allows, it returns truncated: true, the full total_count, and a download_url for the streaming endpoint with the same filters.

The CSV columns are fixed in this order:

decision_id, stamp, necessary, preferences, statistics, marketing,
method, ver, utc, region, page_url, created_at, replaces_id

Booleans use true and false, timestamps use ISO-8601, and missing values produce empty cells. Visitor-influenced values beginning with =, +, -, @ or a control character receive a quote prefix to prevent spreadsheet formula execution.

Both paths accept inclusive from and to bounds in strict ISO-8601 format. An inverted range is rejected.

For one visitor’s history, pass the record id from their consent cookie as record_id to the inline export. It follows the decision chain within your product; an id from another product returns an empty chain. This export covers Consent records only. Other information you hold about that person must be handled separately when answering an access request.

A successful export emits consent.records.exported with the actor, surface and row count. A client-aborted download does not emit a successful-export event.

Retention

Item
Lifetime
Effect
Consent cookie
12 months
Expiry prompts the visitor to choose again
Consent record
1095 days from creation
A daily job deletes expired records per product
Retired signing key
1125 days from retirement
Keeps signing keys available beyond record retention

These periods are implemented defaults and are not configurable. The 1095-day record period was chosen for consent accountability; it is not a universal GDPR duration. Your own retention requirements depend on your processing and jurisdiction.

The cleanup job never removes active keys, and the database prevents deletion of a key still referenced by a record.

Erasure

Consent’s erasure operation is product-wide. It deletes the product’s Consent tables in one transaction, following their foreign-key dependencies, with no Consent tombstone. Organization-wide erasure resolves into a request for each product.

End-user erasure cannot select Consent rows by a person’s identity because no such identifier is stored. A visitor can instead locate their decision chain with the record id in their cookie. See Data and privacy for the wider export and erasure model.

Next steps

Was this page helpful?
Esc

Start typing to search the docs.

↑↓navigate↵select