# Install FlowConsent on Astro

Install FlowConsent on Astro: paste the snippet at the top of your base layout's <head> with is:inline, then turn on SPA mode if you use ClientRouter.

> Canonical: https://www.flowconsent.com/en/doc/install-astro
> Last updated: 2026-10-01
On Astro, the FlowConsent snippet goes at the very top of the `<head>` in your **base layout** (often `src/layouts/Layout.astro`), with the `is:inline` directive on each `<script>` tag so Astro leaves them alone. It takes two steps, plus a third if your site uses View Transitions (`<ClientRouter />`): navigation then happens without a page reload, so you must turn on **SPA mode**.

## Before you start

- An account on [app.flowconsent.com](https://app.flowconsent.com) (free Free plan, no credit card, up to 25,000 sessions per month).
- A banner created and deployed. On the Free plan, deployment goes through your own Cloudflare account ([Cloudflare guide](/en/doc/cloudflare-deployment)); on Pro and Enterprise it takes one click.
- Access to your Astro project's source code.

## Step 1: Copy the snippet

Open **Builder → Deployment → Integration** and copy the snippet from the **HTML / No-code** tab. It has two parts, in this order: the Google Consent Mode v2 stub (`denied` defaults), then the banner loader.

## Step 2: Paste it in the base layout with `is:inline`

Open the layout component that renders the `<html>` and `<head>` for all your pages. Astro projects usually keep layouts in `src/layouts/`, but that is a convention, not a rule: look for the file your pages share. Paste the snippet **right after the opening `<head>` tag**, before any other script, and add `is:inline` to both `<script>` tags:

```html title="src/layouts/Layout.astro"
<html lang="en">
  <head>
    <script is:inline>
    // FlowConsent Loader - place BEFORE any other script in the <head>
    window.dataLayer=window.dataLayer||[];
    function gtag(){dataLayer.push(arguments);}
    gtag('consent','default',{
      'ad_storage':'denied',
      'analytics_storage':'denied',
      'ad_user_data':'denied',
      'ad_personalization':'denied',
      'wait_for_update':500
    });
    gtag('set','url_passthrough',true);
    gtag('set','ads_data_redaction',true);
    </script>
    <!-- FlowConsent CMP -->
    <script is:inline src="https://YOUR-LICENSE-CODE.consent.flowconsent.com/cookie-manager.js?code=YOUR_LICENSE_CODE"></script>

    <meta charset="utf-8" />
    <title>{title}</title>
    <!-- your other tags and scripts come after -->
  </head>
  <body>
    <slot />
  </body>
</html>
```

Why `is:inline`? By default Astro processes `<script>` tags: it transforms, bundles and moves them. With `is:inline`, the script is rendered into the HTML **exactly as written**, where you put it. That matters here: the Consent Mode stub must run immediately, at the top of the page, before any tracking tag.

If your pages do not all share one layout, repeat this in every root layout. Then rebuild and redeploy the site.

## Step 3: Turn on SPA mode if you use ClientRouter

> [!WARNING]
> Astro's `<ClientRouter />` component (imported from `astro:transitions`, and called `<ViewTransitions />` before Astro 5) replaces standard navigation with a client-side router: pages change **without a full reload**, through `history.pushState`. The banner therefore does not run again on each page. Turn on **SPA mode** in the Builder's **Settings** tab, then redeploy the banner: consent is re-checked on every client-side navigation.

During a navigation, Astro keeps `<head>` scripts that also exist on the new page, so your snippet, identical on every page, stays in place without running again. Do not add `data-astro-rerun` to its tags. SPA mode is explained in detail in the [Next.js and React SPA guide](/en/doc/nextjs-integration).

Without `<ClientRouter />`, an Astro site is a classic multi-page site: every click reloads the page and SPA mode is not needed.

## Tracking scripts belong in Services

Do not paste Google Analytics, Meta Pixel or other trackers directly into the layout: they would fire before the visitor chooses. Declare them in **Builder → Services** and the banner loads them only after consent. If you use Google Tag Manager, do not load FlowConsent from GTM (it would arrive too late): place the snippet **above** the GTM container, in the same `<head>`. Details in the [Google Consent Mode guide](/en/doc/google-consent-mode).

## Verify the installation

1. Open the live site in a private window: the banner appears.
2. In the developer tools' **Network** tab, no request to a third-party service goes out before you click **Accept**.
3. With `<ClientRouter />`, navigate across several pages and check that nothing fires there either.
4. Run the [setup wizard](/en/doc/setup-wizard) (Builder → Integration): it checks the live page (loader present with the right license code, Consent Mode stub present and placed before every Google tag).
5. Finish with a refusal scan from the **Compliance** tab ([compliance verification](/en/doc/compliance-verification)).

## Do it from your AI agent (MCP)

FlowConsent has an official MCP server, `https://mcp.flowconsent.com`, usable from Claude, ChatGPT or any MCP client. You connect with OAuth 2.0 using your FlowConsent account, no API key. Your agent fetches the snippet and placement instructions (`get_banner_snippet`, `get_setup_instructions`), verifies the installation with a real scan (`verify_consent_compliance`) and can set up recurring monitoring (`monitor_compliance`). You, or your coding agent, edit the layout: the MCP server provides the snippet, the instructions and the verification.

Example request:

> Give me my banner's snippet for my Astro site, tell me where to put it in my layout, then check that it is installed correctly on https://mysite.com

Learn more: [MCP server](/en/doc/mcp-server) and [FlowConsent for AI agents](/en/mcp).

## Frequently asked questions

### Why does the banner stop working after a navigation?

Your site most likely uses `<ClientRouter />`, so the page does not reload. Turn on SPA mode in **Builder → Settings**, redeploy the banner and test again in a private window.

### Can I use a regular `<script>` without `is:inline`?

No. Without `is:inline`, Astro processes the script and no longer guarantees it sits at the top of the `<head>` or runs immediately. Prior blocking requires the snippet to run before any tracker.

### Do I need a specific Astro adapter or integration?

No. The snippet is plain HTML: it works in static mode and with server rendering, whatever the host (Vercel, Netlify, Cloudflare…).

### My Astro site uses React or Vue islands. Does that change anything?

No, as long as navigating between pages reloads the page. Only `<ClientRouter />` requires SPA mode. Interactive islands do not need to load FlowConsent themselves.
