Verifying a Consent Evidence Certificate
A Consent Evidence certificate (cert_v: 1, or the record-only cert_v: 2) is built to be
checked without trusting AdPriva, and without AdPriva existing. Everything a checker needs is inside the certificate, in the Legal
Bundle export the controller keeps, in a public key registry, and on a public blockchain.
What a certificate proves: this consent wording, these checkbox states, were captured at this time and have not been altered since. It does not prove who the person was, or that consent was freely given; that stays with the controller.
What you need
- the certificate:
EV-….json, downloaded from the console or fromGET https://api.adpriva.com/public/evidence/<evidence_id>; - the Legal Bundle export it names:
LB-….json, downloaded from the console or fromGET https://api.adpriva.com/public/legal-bundles/<LB-id>; - Node.js 20 or newer, and network access to the Horizen public RPC. AdPriva is never contacted.
Run the verifier
AdPriva’s reference verifier, adpriva-verify, is a small MIT-licensed Node.js tool with no
dependencies. Its repository, AdPriva/consent-verifier, is in review before its public release;
until then it is available to customers on request. The checks below are the complete procedure,
so an independent implementation can follow them too.
adpriva-verify EV-….json --bundle LB-….json --claimed-at 2026-08-03T14:12:09.412Z
--claimed-at is the time the controller says the consent was given (for example, from its CRM).
Add --json for a machine-readable report.
The seven checks
| # | Check | What is verified |
|---|---|---|
| 1 | Schema | The file is a cert_v: 1 or cert_v: 2 certificate: exact fields and formats, the interaction assessment allowed for its version, no duplicate keys. |
| 2 | Signature | An Ed25519 signature over the certificate’s canonical content, by a key listed in AdPriva’s published key registry (GET https://api.adpriva.com/public/consent-keys) and valid at the certificate time. Keys are never removed from the registry. |
| 3 | Leaf | The Merkle leaf is recomputed from the content. Change one byte and it no longer matches. |
| 4 | Merkle path | The path folds the leaf up to the batch’s Merkle root. |
| 5 | Anchor | On the Horizen chain (chain id 26514), the transaction succeeded and emitted Anchored(root) from AdPriva’s published contract, sent by AdPriva’s published address, in the stated block at the stated time. |
| 6 | Bundle | The Legal Bundle export hashes to the bundle_hash the certificate binds. Its consent text decides whether the text shown on the page matched (MATCH) or not (TEXT_MISMATCH), and that must equal what the certificate says. |
| 7 | Timing | The anchor came within the published window (60 minutes) after the event. With --claimed-at, the certification time must also be within 10 minutes of the claimed consent time. A certificate made later for an older consent is flagged as a possible re-certification. |
Each check reports PASS, FAIL, FLAG (worth a human look, for example a truthful TEXT_MISMATCH or
a late anchor), SKIP or ERROR. The verdict is PASS, FLAGGED, INCOMPLETE (anchor still pending or no
bundle supplied) or FAIL.
Record-only certificates (cert_v: 2)
A cert_v: 2 certificate records a consent form submitted without consent through the site’s
consent banner, on a form the controller opted in. No interaction signals were collected, so its
interaction assessment is always NOT_AVAILABLE: it says nothing about whether a person or a bot
submitted the form. Every other field and all seven checks are the same as for cert_v: 1.
Use verifier v0.2.0 or newer. An older verifier refuses a cert_v: 2 certificate at step 1 with
“cert_v must be 1”, rather than misreading it.
The exact rules
Canonicalization (how text and JSON are normalized before hashing) is specified in the canonicalization annex that ships with the verifier, and pinned by a fixture suite that the JavaScript, Go and Python implementations and three browser engines all pass.
The registry also lists the anchor contract (0x7b6a7eb310d30c338c9ecb575f439c1a93fcb217 on
Horizen, chain id 26514) and the one address allowed to anchor (0xc0bd23fbde06d43ff699aa23cbf69f1b3de18663),
so step 5 can be checked against any Horizen RPC or block explorer.
Known limits
- A certificate attests what the AdPriva tag observed in the page. A site that deliberately feeds the tag a doctored page is outside what any client-side witness can rule out (spec T8).
- A consent event fabricated on day one is still a consent event to the tag. The interaction
assessment raises the bar, but the claim is strictly “unaltered since T” (spec T7). A
record-only
cert_v: 2certificate has no interaction assessment at all. - Anchoring currently uses a single chain (Horizen). A second, independent anchor is planned.