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):
<!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:
<!-- 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:
- Change
typefromtext/javascript(or remove it) totype="text/plain". - Add
data-cookieconsent="CATEGORY"where category isanalytics,marketing, orpreferences. - 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):
<!-- 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:
<!-- 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:
getcookies_domain_id: "YOUR_DOMAIN_ID"Gatsby
Add to gatsby-ssr.js to inject into the <head>:
// 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):
---
// 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):
<!-- _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:
<!-- 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:
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:
// 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:
<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:
// 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:
<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:
<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:
// 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
- Open your site in an incognito/private window.
- Confirm the consent banner appears on the first page load.
- Open DevTools > Network and verify tracking scripts wait for consent.
- Accept consent and confirm trackers load.
- For SPAs, navigate between routes and verify the banner state persists without reloading.
- Check your GetCookies dashboard under Consent Logs to see the test consent recorded.
Troubleshooting
Banner not appearing
- 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.
Scripts still firing before consent
- Unwrapped scripts: Ensure all tracking scripts have
type="text/plain"and adata-cookieconsentattribute. - 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
beforeInteractivestrategy (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.