Server-Side Enforcement
Client-side blocking (Consenti's widget not loading a script until consent is granted) covers the browser. It doesn't cover a server-side tag manager, an edge-injected pixel, or a backend event pipeline forwarding events to an ad platform — those need to ask Consenti's API directly before firing. GET /consent/:visitorId/verifyis built for exactly this: it's fetch-based, has no server-side SDK dependency, and works identically from a Node backend, a Cloudflare Worker, or a Vercel Edge Function.
The endpoint
GET /consenti/api/v1/consent/:visitorId/verifyReturns { valid: boolean, reasons: string[], ... }. valid is false whenever the profile has changed since the visitor decided, the consent has expired, or — when consentSigningKeyis configured — the stored signature doesn't match (hmac_invalid). Treat any of these the same way you'd treat "no valid consent": don't fire the tag.
Cookie header.Pattern: gate a tag before firing it
async function isConsentValid(visitorId: string, cookieHeader: string): Promise<boolean> {
const res = await fetch(
`https://your-domain.com/consenti/api/v1/consent/${visitorId}/verify`,
{ headers: { Cookie: cookieHeader } },
)
if (!res.ok) return false
const { valid } = await res.json() as { valid: boolean }
return valid
}
// Before forwarding an event to an ad platform's server-side API:
if (await isConsentValid(visitorId, req.headers.get('cookie') ?? '')) {
await adPlatform.sendServerEvent(payload)
}Edge-worker example
Both Cloudflare Workers and Vercel Edge Functions run on the standard Fetch API (the same Request/Response globals Consenti itself is built on), so the pattern above needs no adaptation — only the surrounding handler shape differs:
export default {
async fetch(req: Request): Promise<Response> {
const visitorId = new URL(req.url).searchParams.get('vid')
if (!visitorId) return new Response('Missing vid', { status: 400 })
const verifyRes = await fetch(
`https://your-domain.com/consenti/api/v1/consent/${visitorId}/verify`,
{ headers: { Cookie: req.headers.get('cookie') ?? '' } },
)
const { valid } = await verifyRes.json() as { valid: boolean }
if (!valid) {
return new Response(null, { status: 204 }) // no-op: consent not valid, don't fire the pixel
}
// Forward to the actual pixel/tag endpoint only when valid
return fetch('https://ad-platform.example.com/pixel', { method: 'POST', body: req.body })
},
}Pattern: gate a backend event pipeline
The same check works as a guard clause anywhere in a server-side event pipeline — before writing to a data warehouse row, before publishing to a Kafka topic, before calling a CDP's server-side API. Cache the verify result for the lifetime of a single request/batch rather than calling it per-event if you're processing many events for the same visitor at once.