Docs

Cookies, scan & verify

AdminUpdated Sep 15, 2026

Cookies, scan & verify

This page covers three related capabilities on a single site (cbid): reading its categorized cookie declaration, triggering the crawler that builds that declaration, and proving domain ownership so domain-gated features (consent export, signed receipts) unlock. All three live under /v1/sites/:cbid/..., require an API key (Authorization: Bearer fck_… or X-API-Key: fck_…), and are checked against the sites scope — sites:read for the GETs below, sites:write for the POSTs. None of them require consent:*, even though "cookies" sounds consent-adjacent: this is declaration/crawl metadata, not consent-decision data. A cbid that doesn't belong to your org behaves exactly like a nonexistent one (404), never a 403 or 409 — the API never confirms another org's resource exists.

Get the cookie declaration

GET /v1/sites/{cbid}/cookies

Scope: sites:read

Returns the latest categorized cookie snapshot — the same data a cookieTable banner element renders and what a generated cookie-policy page lists. This isn't purely scan-driven: the embed also passively reports cookie names (never values) and third-party script hosts it observes on real visitor traffic, merging them into this snapshot between explicit scans.

Param

In

Type

Description

cbid

path

string

The site identifier.

curl https://api.cookiemunch.net/v1/sites/acme-com-9f3k/cookies \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY"
{
  "updatedAt": 1719858421000,
  "cookies": [
    {
      "name": "_ga",
      "domain": ".acme.com",
      "category": "statistics",
      "purpose": "Registers a unique ID for statistical purposes.",
      "provider": "Google Analytics",
      "expiry": "2 years"
    },
    { "name": "session_id", "category": "necessary" }
  ]
}

category is one of necessary, preferences, statistics, marketing, or unclassified (observed but not yet matched to a known tracker signature). domain, purpose, provider, and expiry are omitted when unknown. updatedAt is 0 (epoch) if nothing has ever been scanned or observed.

Errors: 404 — site not found (or not yours). 501 — cookie declarations aren't configured on this deployment.

const decl = await client.sites.cookies('acme-com-9f3k');
// decl.updatedAt, decl.cookies[]

Start a scan

POST /v1/sites/{cbid}/scan

Scope: sites:write

Kicks off an asynchronous Playwright crawl of the site's homepage to (re)build its cookie declaration. The call returns immediately; the crawl runs in the background and results land in GET /v1/sites/{cbid}/cookies once it finishes. Before launching a real browser at the domain, the server SSRF-screens the resolved address (a domain that resolves to a private, loopback, link-local, or cloud-metadata address is refused, silently, rather than crawled).

Param

In

Type

Description

cbid

path

string

The site identifier.

curl -X POST https://api.cookiemunch.net/v1/sites/acme-com-9f3k/scan \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY"

202 Accepted:

{ "status": "scanning" }

If a scan for this cbid is already in flight, the request is rejected rather than queued a second time:

409 Conflict:

{ "status": "already-scanning" }

Errors: 404 — site not found. 409 — a scan is already running for this site. 501 — cookie scanning isn't configured on this deployment (the crawler is an optional server component; a self-host without Playwright wired up returns this).

const { status } = await client.sites.scan('acme-com-9f3k'); // 'scanning'

Get scan status

GET /v1/sites/{cbid}/scan

Scope: sites:read

Poll this after starting a scan to know when results are ready.

curl https://api.cookiemunch.net/v1/sites/acme-com-9f3k/scan \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY"
{ "status": "idle", "lastScannedAt": 1719858421000 }

Field

Type

Description

status

"idle" | "scanning"

Whether a crawl is currently in flight for this site.

lastScannedAt

epoch-ms | null

When the most recent completed scan finished; null if none has ever completed.

Finishing a scan (whether or not the cookie set changed) fires a scan.completed webhook; if the set of cookie names differs from the previous crawl, scan.cookies_changed also fires (see webhooks).

Errors: 404 — site not found. 501 — cookie scanning not configured.

const status = await client.sites.scanStatus('acme-com-9f3k');

Verify domain ownership

POST /v1/sites/{cbid}/verify

Scope: sites:write

Proves you control the site's domain, which unlocks domain-gated routes: consent CSV export and machine-fetched signed receipts (see the consent/sites reference). The token to place is on the site resource itself (verifyToken, from GET /v1/sites/{cbid}); it's a stable per-site string in the form fcv_ + 24 hex characters.

Field

Type

Required

Description

method

"dns" | "meta" | "file"

yes

Which challenge to check.

Method

Check performed

dns

A TXT record cookiemunch-verify=<verifyToken> (the bare token is also accepted) exists at the domain.

meta

The homepage serves <meta name="cookiemunch-site-verification" content="<verifyToken>">.

file

https://{domain}/.well-known/cookiemunch-verify.txt contains <verifyToken>.

curl -X POST https://api.cookiemunch.net/v1/sites/acme-com-9f3k/verify \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "method": "dns" }'

Success (also flips site.verified to true server-side):

{ "verified": true, "method": "dns" }

Failure — the site's verification state is left unchanged, so you can retry after fixing DNS/meta/file:

{ "verified": false, "reason": "TXT record not found or did not match" }

Note that a failed check is still a 200verified: false is a normal outcome, not an error. Only malformed requests and infrastructure gaps are non-2xx.

Errors: 400method missing or not one of dns/meta/file. 404 — site not found. 501 — domain verification isn't configured on this deployment (no verify network/DNS dependency injected).

const result = await client.sites.verify('acme-com-9f3k', 'dns');
if (result.verified) { /* domain-gated routes now unlocked */ }

Next: banner library to manage what the banner actually shows, or API keys, members, webhooks & usage for the scan.* webhook event catalogue.

Was this page helpful?