Reference
Cookie Consent Banner — Contract
The engine inspects the rendered HTML at render time. If it finds a
#cookie-bannerelement, it injects the consent-gated analytics variant (withacceptCookies()/declineCookies()handlers). If no banner is found, it injects Google's standard GA snippet directly — analytics loads unconditionally andgtag()is globally available for custom event tracking.
When site.analytics is set in site.yaml, the Worker automatically injects analytics into <head>. Your job is to decide whether you need consent gating, and if so, provide a banner whose markup matches the contract below. Styling is yours; the IDs are fixed.
Both paths globalize window.dataLayer and window.gtag synchronously, so custom event tracking (gtag('event', 'cta_click', {...})) works from anywhere on the page — including before consent is granted on banner-equipped sites. Pre-consent events queue harmlessly in dataLayer and only travel to Google after acceptance loads gtag.js.
Required element IDs
The injected JS binds to these IDs by name. All three are required — missing any breaks the consent flow.
| Element | ID | Purpose |
|---|---|---|
Container <div> |
cookie-banner |
Holds the banner. Must start hidden (style="display:none"). The JS shows it only if the user hasn't already consented. |
Accept <button> |
cookie-accept |
Triggers acceptCookies() (injected by the Worker). |
Decline <button> |
cookie-decline |
Triggers declineCookies() (injected by the Worker). |
Minimal contract-compliant banner
Place inside <body> in templates/layout.html, before any other content:
<div id="cookie-banner" style="display:none" class="fixed bottom-0 left-0 right-0 z-50 p-4 bg-secondary-900 text-white">
<div class="max-w-4xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4">
<p class="text-sm text-secondary-300">
We use cookies to improve your experience and analyze site traffic.
<a href="/privacy" class="underline hover:text-white">Learn more</a>
</p>
<div class="flex gap-3 shrink-0">
<button id="cookie-decline" class="px-4 py-2 text-sm border border-secondary-600 rounded-lg hover:border-secondary-400 transition-colors">
Decline
</button>
<button id="cookie-accept" class="px-4 py-2 text-sm bg-primary-600 rounded-lg hover:bg-primary-500 transition-colors font-medium">
Accept
</button>
</div>
</div>
</div>
Rules
- Never write the consent JS yourself.
acceptCookies()anddeclineCookies()are injected automatically whensite.analyticsis set. Writing them manually causes conflicts. - Banner must start hidden (
style="display:none"). The injected JS reveals it only when consent hasn't been recorded. - All three IDs must be present —
cookie-banner,cookie-accept,cookie-decline. - Style freely with Tailwind — position, colours, layout are all yours. The only constraint is the IDs.
- If no banner is needed (e.g. the site isn't subject to GDPR), omit the banner HTML entirely; the engine then injects Google's standard GA snippet directly into
<head>and analytics loads unconditionally.