How to add a cookie consent banner to a Docusaurus site
In Docusaurus, add the snippet as the first entry of the scripts field in docusaurus.config.js: Docusaurus prints those tags in the head of every page, before the head tags that plugins inject. If the site uses the gtag option of the classic preset, either drop the snippet's defer so Consent Mode defaults run first, or replace the plugin with a marked script.Steps
Where does the snippet go in Docusaurus?
The scripts field of docusaurus.config.js takes URLs or objects of attributes, and Docusaurus inserts the resulting <script> tags in the head of every page. The plugin documentation adds that the head tags plugins inject come after the scripts added by the config, so an entry here runs before analytics plugins:
js// docusaurus.config.jsexport default {// ...scripts: [{src: "https://cookiequiet.com/cq.js",defer: true,"data-site": "YOUR_SITE_KEY","data-consent-mode": "1","data-auto-block": "1",},],};
Use scripts rather than headTags for this: both print to the head, but scripts is the field Docusaurus documents for script tags, and its object form accepts any attribute. Do not load the banner as a client module either: client modules are bundled into the app and run after it, while the banner reads its settings from its own tag.
What about the gtag option of the classic preset?
Many Docusaurus sites set gtag: { trackingID: "G-..." } in @docusaurus/preset-classic. The plugin is active only in production builds, and it injects the Google tag as head tags: the external gtag.js with async, then an inline script that calls gtag('config') straight away. That inline script runs while the page is parsed, before a deferred script. Two ways to put consent first:
Keep the plugin, use Consent Mode. Remove defer: true from the Cookiequiet entry. The banner then runs where it stands, before the plugin's tags, and sets every Google consent type to denied before gtag('config'). Google Analytics loads with analytics_storage denied and sets no _ga cookie until the visitor accepts; Cookiequiet sends the update after each choice. The Google Analytics 4 guide explains what Google receives in that state.
Drop the plugin, load GA only after consent. Remove the gtag option and add your own file as a marked script:
jsscripts: [{ src: "https://cookiequiet.com/cq.js", defer: true, "data-site": "YOUR_SITE_KEY", "data-consent-mode": "1", "data-auto-block": "1" },{ src: "/js/analytics.js", type: "text/plain", "data-cq-category": "analytics" },],
js// static/js/analytics.jsvar s = document.createElement("script");s.async = true;s.src = "https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX";document.head.appendChild(s);window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag("js", new Date());gtag("config", "G-XXXXXXX");
Cookiequiet runs the file when analytics is granted, and at once on later visits where the stored choice includes it. Nothing from Google loads before that. Any other tracker can follow the same pattern; the guide on blocking scripts lists the markup for embeds.
What about client-side navigation?
A Docusaurus site is a single-page app after the first load. The snippet runs once per full load and the stored choice stays applied, so the banner does not come back on each page. If you send page views yourself, a client module's onRouteDidUpdate runs after each route renders, and on the first render too; check consent there with window.Cookiequiet.get(), whose c array lists the granted categories, or keep the categories from the cq:consent event that Cookiequiet dispatches on window each time it applies a choice. Docusaurus notes that hash changes also trigger these lifecycles, so compare the pathname before sending.
How do I add the Cookie preferences link?
Footer items accept an html field that is rendered as given:
jsthemeConfig: {footer: {links: [{title: "Legal",items: [{ html: '<a href="#cq-preferences" data-cq-show-preferences>Cookie preferences</a>' },],},],},},
How do I test it?
- Run
npm run buildthennpm run serve: the gtag plugin does nothing in development, so test the production build. - View the page source:
cq.jsis the first script in the head. - Open the site in a private window and click Reject all: no
_gacookie, onlycq_consent. - Clear the cookies, click Accept all, reload:
_gaappears and the Realtime report shows the visit. - Check the consent log in the dashboard.
Documentation sites often serve a global audience: geo-targeting can show the banner only in regulated countries, and it is included in the free plan, which covers one website. Starter is €3 per website per month with unlimited pageviews.
Questions
Sources
- Docusaurus: docusaurus.config.js (scripts, headTags, clientModules)
- Docusaurus: Plugin lifecycle APIs (injectHtmlTags order)
- Docusaurus: plugin-google-gtag
- Docusaurus source: plugin-google-gtag injectHtmlTags
- Docusaurus: Client-side architecture (onRouteDidUpdate)
- Docusaurus: Theme configuration (footer html items)