How to add a cookie consent banner to an Astro site
In Astro, put the snippet in the head of your shared layout (src/layouts/Layout.astro) as the first script, with is:inline so Astro renders it exactly as written. Mark Google and Meta tags in the same layout with type="text/plain" and data-cq-category, and keep marked tags in the layout rather than in pages when you use the ClientRouter.Steps
Where to paste the snippet in Astro
Astro layouts are components that provide the page shell, with <html>, <head>, <body> and a <slot /> for the page content. The snippet goes in the head of that layout, before any other script. Astro processes a <script> only when its sole attribute is src; ours carries data attributes, so Astro leaves it alone, but is:inline makes the intent explicit:
astro---// src/layouts/Layout.astroconst { title } = Astro.props;---<html lang="en"><head><meta charset="utf-8" /><script is:inline src="https://cookiequiet.com/cq.js" data-site="YOUR_SITE_KEY" data-consent-mode="1" data-auto-block="1" defer></script><meta name="viewport" content="width=device-width" /><title>{title}</title></head><body><slot /></body></html>
Every page that uses the layout, including Markdown pages that name it in their layout frontmatter, now loads the banner. If your project has several layouts, put the line in each, or in a small Head.astro component they all include.
How to handle the tags your site loads
Marked tags in the layout. Add the tags after the snippet, with is:inline, type="text/plain" and a category. Cookiequiet runs them when the category is granted, or at once on later visits when a stored choice includes it:
html<script is:inline type="text/plain" data-cq-category="analytics" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script><script is:inline type="text/plain" data-cq-category="analytics">window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', 'G-XXXXXXX');</script>
The Meta Pixel base code gets data-cq-category="marketing"; its noscript image must be removed, as the Meta Pixel guide explains.
Consent Mode instead of marking. To keep the Google tag loading with denied defaults and cookieless pings, place Google's default consent block (an inline script) between the snippet and the Google tag, as shown in the Google Analytics 4 guide. Cookiequiet sends the update after each choice.
Partytown. Keep cq.js on the main thread: it needs the document. If you move the Google tag into a Partytown worker, forward dataLayer.push so the consent commands reach it.
Embeds. Write iframes with data-cq-src instead of src. Facade components that build the YouTube player on click create the iframe with JavaScript; the auto-blocker holds youtube.com/embed under marketing until that category is granted. See YouTube embeds and consent.
What changes with the ClientRouter
With view transitions, Astro swaps the page content without a full load. The snippet in the head keeps running across navigations, the stored choice stays applied and the banner does not reappear. Two consequences:
- Marked scripts inside a page body loaded by client-side navigation are not activated until the next consent event, because Cookiequiet activates marked tags when a choice is applied on load and after each choice. Keep marked tags in the layout.
- Island scripts that need the choice should read
window.Cookiequiet.get()(thecarray lists the granted categories) and subscribe withwindow.Cookiequiet.on(callback), which returns an unsubscribe function.
How to add the Cookie preferences link
In src/components/Footer.astro or wherever the footer lives:
html<a href="#cq-preferences" data-cq-show-preferences>Cookie preferences</a>
How to test
- Run
astro dev(orastro buildthenastro preview) and open the site in a private window. - Click Reject all: the cookies are
cq_consentand nothing from Google or Meta. - Clear the cookies, click Accept all, reload: the marked scripts run.
- With the ClientRouter, navigate between pages and check that the choice holds.
- Check the consent log in the dashboard.
What is specific to Astro
- Static output. The banner is a client script; the built site works on any static host (Netlify, Vercel, Cloudflare Pages, GitHub Pages). The article on cookie banners for static sites covers the rest.
- Content Security Policy. Allow
https://cookiequiet.cominscript-srcandconnect-src. - Multiple languages. The banner's language follows the visitor's browser, with every string editable per language; it does not read the page's
lang. - Content collections and Markdown. Pages rendered through the layout need no change; tags pasted inside Markdown content would bypass the layout, so keep tags in the layout.