Cookie consent for Astro

The banner goes in the layout every page shares, as an inline script so Astro doesn't bundle or defer it. It holds back your trackers until the visitor chooses, sends Google Consent Mode v2 signals, and stays put across <ClientRouter /> view transitions.

Set it up with your AI agent

Connect the Croombit MCP server to your editor or coding agent and paste this. It creates the site, the cookie categories and the banner, and edits your code.

Using Croombit: create a site for this project and keep the cookie categories it comes with. Write the banner text and publish the banner. Create a TEST publishable key for localhost:3000. This is an Astro site: add cmp.js with is:inline first in <head> of the shared layout, reading the key from PUBLIC_CROOMBIT_KEY, change our analytics <script> tags to type="text/plain" with data-tc-consent, and add a "Cookie settings" link to the footer.

The agent works in TEST. Going live takes two steps in the console: verify your domain and swap in a LIVE key — see going live.

Or by hand

1. Add the tag to your layout

Put the key in .env as PUBLIC_CROOMBIT_KEY (pk_test_… in development, pk_live_… in production). is:inline keeps it exactly where you put it.

---
// src/layouts/Layout.astro — the layout every page uses
const key = import.meta.env.PUBLIC_CROOMBIT_KEY;
---
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <!-- is:inline: Astro must not bundle or defer it -->
    <script is:inline src="https://croombit.com/cmp.js" data-tc-api-key={key}></script>
    <!-- …everything else after it -->
  </head>
  <body>
    <slot />
  </body>
</html>

2. Hold back trackers

Change their type to text/plain and add data-tc-consent. A script with attributes is left as-is by Astro, so it stays inert until the visitor grants that category.

<script type="text/plain" data-tc-consent="analytics" async
        src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
<script type="text/plain" data-tc-consent="analytics">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXX');
</script>

The list on your cookie policy page, the link in your footer component:

<div data-tc-cookie-declaration></div>
<a href="#" data-tc-open-preferences>Cookie settings</a>

Questions

Does it work with view transitions (<ClientRouter />)?

Yes. The banner and the floating button are carried across each navigation, and tagged scripts on the next page run as soon as their category is granted.

Does it work with a static build?

Yes. The tag is plain HTML in every generated page; nothing needs a server.