Back to the help center

Integrations

Custom HTML / Static Sites

Install the banner on any HTML site, static generator, or JavaScript framework

A complete guide to adding the GetCookies consent banner to plain HTML sites, static site generators (Hugo, Jekyll, Gatsby, Astro, 11ty), and JavaScript frameworks (React, Vue, Angular, Svelte).

Prerequisites

  • A GetCookies account with a domain configured for your site.
  • Your Domain ID from the GetCookies dashboard (Domains > Widget Configuration).

Basic HTML Installation

Step 1: Add the Script Tag

Add this to the <head> of every page (or your shared template/layout file):

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Your Site</title>

    <!-- GetCookies - Cookie Banner (load before other scripts) -->
    <script src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async></script>

    <!-- Your other scripts below -->
</head>
<body>
    <!-- Your content -->
</body>
</html>

Step 2: Wrap Tracking Scripts

Any tracking scripts on your page should be wrapped so they wait for consent:

html
<!-- Google Analytics - blocked until analytics consent -->
<script data-cookieconsent="analytics"
        type="text/plain"
        src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script data-cookieconsent="analytics" type="text/plain">
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', 'G-XXXXXXXXXX');
</script>

<!-- Facebook Pixel - blocked until marketing consent -->
<script data-cookieconsent="marketing" type="text/plain">
    !function(f,b,e,v,n,t,s){/* Meta Pixel code */}(window,document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', 'YOUR_PIXEL_ID');
    fbq('track', 'PageView');
</script>

The key pattern is:

  1. Change type from text/javascript (or remove it) to type="text/plain".
  2. Add data-cookieconsent="CATEGORY" where category is analytics, marketing, or preferences.
  3. GetCookies will rewrite these scripts back to executable once the user consents to the matching category.

Static Site Generators

Hugo

Add the script to your base template (typically layouts/_default/baseof.html or layouts/partials/head.html):

html
<!-- In layouts/partials/head.html or baseof.html <head> -->
<script src="https://app.getcookies.co/api/v1/widget/loader.js"
        data-domain-id="YOUR_DOMAIN_ID"
        async></script>

Jekyll

Add to _includes/head.html or your layout file:

html
<!-- In _includes/head.html -->
<script src="https://app.getcookies.co/api/v1/widget/loader.js"
        data-domain-id="{{ site.getcookies_domain_id }}"
        async></script>

Then set getcookies_domain_id in your _config.yml:

yaml
getcookies_domain_id: "YOUR_DOMAIN_ID"

Gatsby

Add to gatsby-ssr.js to inject into the <head>:

javascript
// gatsby-ssr.js
exports.onRenderBody = ({ setHeadComponents }) => {
    setHeadComponents([
        <script
            key="getcookies"
            src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async
        />,
    ]);
};

Astro

Add to your layout component (e.g., src/layouts/Layout.astro):

html
---
// src/layouts/Layout.astro
---
<html>
<head>
    <script
        src="https://app.getcookies.co/api/v1/widget/loader.js"
        data-domain-id="YOUR_DOMAIN_ID"
        is:inline
        async></script>
</head>
<body>
    <slot />
</body>
</html>

The is:inline directive prevents Astro from bundling the script.

Eleventy (11ty)

Add to your base layout (e.g., _includes/base.njk):

html
<!-- _includes/base.njk -->
<head>
    <script src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async></script>
</head>

JavaScript Frameworks (SPAs)

Single-page applications need special handling because the page does not do a full reload on navigation. GetCookies handles this automatically for most SPA frameworks, but here are framework-specific tips.

React (Create React App / Vite)

Add the script to your public/index.html:

html
<!-- public/index.html -->
<head>
    <script src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async></script>
</head>

To listen for consent changes in your React components:

javascript
import { useEffect, useState } from 'react';

function useConsent() {
    const [consent, setConsent] = useState(null);

    useEffect(() => {
        const checkConsent = () => {
            if (window.GetCookies) {
                const current = window.GetCookies.getConsent();
                setConsent(current);
                window.GetCookies.onConsentChange((updated) => {
                    setConsent(updated);
                });
            }
        };

        // GetCookies may not be loaded yet
        if (window.GetCookies) {
            checkConsent();
        } else {
            const interval = setInterval(() => {
                if (window.GetCookies) {
                    clearInterval(interval);
                    checkConsent();
                }
            }, 100);
            return () => clearInterval(interval);
        }
    }, []);

    return consent;
}

Next.js

For Next.js App Router, add to your root layout:

javascript
// app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }) {
    return (
        <html>
        <head>
            <Script
                src="https://app.getcookies.co/api/v1/widget/loader.js"
                data-domain-id="YOUR_DOMAIN_ID"
                strategy="beforeInteractive"
            />
        </head>
        <body>{children}</body>
        </html>
    );
}

Use strategy="beforeInteractive" to ensure the consent banner loads before other scripts.

Vue.js

Add to your public/index.html or index.html:

html
<head>
    <script src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async></script>
</head>

For Nuxt.js, add to nuxt.config.ts:

javascript
// nuxt.config.ts
export default defineNuxtConfig({
    app: {
        head: {
            script: [
                {
                    src: 'https://app.getcookies.co/api/v1/widget/loader.js',
                    'data-domain-id': 'YOUR_DOMAIN_ID',
                    async: true,
                },
            ],
        },
    },
});

Angular

Add to src/index.html:

html
<head>
    <script src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async></script>
</head>

Svelte / SvelteKit

For SvelteKit, add to src/app.html:

html
<head>
    <script src="https://app.getcookies.co/api/v1/widget/loader.js"
            data-domain-id="YOUR_DOMAIN_ID"
            async></script>
    %sveltekit.head%
</head>

Using the JavaScript API

Once the banner is installed, you can use the GetCookies JavaScript API to check and react to consent:

javascript
// Check current consent state
const consent = window.GetCookies?.getConsent();
if (consent?.choices.analytics) {
    // Analytics consent was given -- safe to initialize
}

// Listen for consent changes
window.GetCookies?.onConsentChange(function (consent) {
    if (consent.choices.marketing) {
        // User just accepted marketing -- initialize pixel
    }
});

Content Security Policy (CSP)

If your site uses a Content Security Policy, you need to allow the GetCookies script:

Content-Security-Policy: script-src 'self' https://app.getcookies.co; style-src 'self' https://app.getcookies.co 'unsafe-inline';

See the "Content Security Policy (CSP) errors" article for detailed CSP configuration.

Verify the Installation

  1. Open your site in an incognito/private window.
  2. Confirm the consent banner appears on the first page load.
  3. Open DevTools > Network and verify tracking scripts wait for consent.
  4. Accept consent and confirm trackers load.
  5. For SPAs, navigate between routes and verify the banner state persists without reloading.
  6. Check your GetCookies dashboard under Consent Logs to see the test consent recorded.

Troubleshooting

  • Domain ID: Verify the Domain ID matches your site's domain in the GetCookies dashboard.
  • Script placement: The script must be in the <head> tag, not the <body>.
  • Bundler interference: If using a bundler (Webpack, Vite, Rollup), make sure it is not trying to bundle the external GetCookies script. Use the raw HTML approach or framework-specific external script methods.
  • CSP blocking: Check DevTools > Console for CSP violation errors.
  • Unwrapped scripts: Ensure all tracking scripts have type="text/plain" and a data-cookieconsent attribute.
  • Dynamic script loading: If your code dynamically creates script elements, use the JavaScript API to check consent before loading them.
  • Framework SSR: In server-rendered frameworks, scripts in the initial HTML payload may execute before the banner loads. Use the beforeInteractive strategy (Next.js) or equivalent.

SPA route changes cause issues

  • GetCookies handles most SPA frameworks automatically. If you notice issues on route changes, see the "Single-page apps and route changes" article for detailed troubleshooting.

Still stuck?

Email [email protected] with your domain and what you tried. Signed-in customers can also open a ticket from the dashboard.