How to add a cookie consent banner to a Gatsby site
In Gatsby, add the snippet to the head of every page from gatsby-ssr.js with onRenderBody and setHeadComponents, so it is in the static HTML before Gatsby's own scripts. Mark analytics and advertising tags in the same place with type="text/plain" and data-cq-category, and send route-change page views from gatsby-browser.js only when the category is granted.Steps
Where does the snippet go in Gatsby?
Gatsby renders every page to static HTML at build time. The server rendering APIs in gatsby-ssr.js let you add elements to that HTML: onRenderBody receives setHeadComponents, which adds components to the head of every page. That is where the snippet belongs, because it is then in the HTML before Gatsby's JavaScript bundles.
jsx// gatsby-ssr.jsimport * as React from "react";export const onRenderBody = ({ setHeadComponents }) => {setHeadComponents([<scriptkey="cookiequiet"src="https://cookiequiet.com/cq.js"data-site="YOUR_SITE_KEY"data-consent-mode="1"data-auto-block="1"defer/>,]);};
Do not use Gatsby's <Script> component for this. Its strategies (post-hydrate, idle and off-main-thread) all load after hydration, which is too late for a script that has to run before the tags it controls.
Plugins that add head tags. If a plugin also calls setHeadComponents, export onPreRenderHTML to put the snippet first. Gatsby documents this hook for reordering what other plugins added:
jsxexport const onPreRenderHTML = ({ getHeadComponents, replaceHeadComponents }) => {const head = getHeadComponents();head.sort((a, b) => (a && a.key === "cookiequiet" ? -1 : b && b.key === "cookiequiet" ? 1 : 0));replaceHeadComponents(head);};
When several plugins implement onPreRenderHTML, the last one wins, so check the built HTML.
How do I block my own tags until consent?
Marked tags in gatsby-ssr.js. Add them in the same setHeadComponents array, after the snippet. Cookiequiet turns them into running scripts when the category is granted, and at once on later visits when the stored choice includes it:
jsx<scriptkey="ga4-config"type="text/plain"data-cq-category="analytics"dangerouslySetInnerHTML={{ __html: "/* your Google tag configuration, unchanged */" }}/>
The external gtag.js script gets the same type and data-cq-category. The Google Analytics 4 guide shows both tags and the Consent Mode alternative.
Plugins that print a tracker. A plugin that writes a tracking script into the HTML at build time runs before any consent script can stop it, unless it is a Google tag loading under Consent Mode with denied defaults. For other trackers, remove the plugin and add the marked tag yourself. Scripts that are created later by JavaScript (a tag manager, a chat widget) are held by the auto-blocker when they come from one of the about 80 trackers it knows.
What changes with client-side navigation?
After the first load, Gatsby navigates without reloading the page. The snippet runs once per full load and the choice stays applied, so the banner does not reappear. Two consequences:
- Marked scripts are activated when a choice is applied on load and after each choice. Keep them in
gatsby-ssr.js, not inside page components. - Page views on route changes are your code's job. Gatsby calls
onRouteUpdateingatsby-browser.json every route change, including the initial load. Send the page view only when analytics is granted.
Cookiequiet dispatches a cq:consent event on window whenever it applies a choice (a stored one on load, a new one after a click, or every category in regions where the banner is not shown). Its detail.categories lists the granted categories:
js// gatsby-browser.jslet analytics = false;window.addEventListener("cq:consent", (e) => {analytics = e.detail.categories.indexOf("analytics") >= 0;});export const onRouteUpdate = ({ location }) => {if (!analytics) return;// send your page view for location.pathname here};
window.Cookiequiet.get() returns the choice in force (its c array lists the categories): the stored one, or a: "geo" with every category where geo-targeting shows no banner. It returns null while no choice applies yet.
How do I add the Cookie preferences link?
Render a plain anchor in the footer component. A hash link does not need Gatsby's <Link>:
jsx<a href="#cq-preferences" data-cq-show-preferences>Cookie preferences</a>
How do I test it?
- Run
gatsby buildthengatsby serve:gatsby-ssr.jsonly affects the built HTML, so test the build rather thangatsby develop. - View the page source: the Cookiequiet script must be the first script in the head.
- Open the site in a private window and click Reject all. The cookies should be
cq_consentand nothing from Google or Meta. - Clear the cookies, click Accept all, reload: the marked scripts run. Navigate between pages and check that the choice holds.
- Open the consent log in the dashboard.
The cookie scanner lists what the deployed site sets before consent. Cookiequiet is free for one website with geo-targeting included, and Starter is €3 per website per month with no pageview limit.
What else is specific to Gatsby?
- Content Security Policy. Allow
https://cookiequiet.cominscript-srcandconnect-src: the banner fetches its configuration, the geo lookup and the consent records from that origin. - Partytown. Keep
cq.json the main thread. It reads the document and controls the scripts on it. - Static hosting. The banner needs no server code, so Netlify, Cloudflare Pages or any static host works.