Platforms

How to add a cookie consent banner to a Drupal site

Drupal has no admin field for head code, so the snippet goes in your theme's copy of html.html.twig, right after the opening head tag, or in a small module that attaches it with hook_page_attachments(). Clear the caches, uninstall any other consent module, and mark the tags you control with type="text/plain" and a data-cq-category; the rest of the setup is in the Cookiequiet dashboard.
Published 21 October 2026 · By the Cookiequiet team · Markdown

Steps

Copy your snippetIn the Cookiequiet dashboard, open your website and copy the install snippet: one script tag with your site key, data-consent-mode and data-auto-block set to 1, and defer.
Copy html.html.twig into your themeCopy the html.html.twig your theme uses (from the base theme, or core/modules/system/templates/) into your own theme or sub-theme's templates folder. Never edit core or a contributed theme in place.
Paste the snippet after the head tagPaste the snippet on the line right after the opening head tag, above the head, CSS and JS placeholders. Or attach it from a custom module with hook_page_attachments() as shown in this guide.
Clear the cachesGo to Configuration, then Development, then Performance and click Clear all caches, or run drush cr. Drupal only picks up a new template after a cache rebuild.
Uninstall other consent modules and set the Google tagUninstall EU Cookie Compliance, Klaro or any other banner module. If the Google Tag module prints your tag, tick Enforce Privacy Consent Policy in the container's advanced settings.
Mark the tags you pasted yourselfFor a Meta Pixel or analytics block added in a template or a Full HTML block, change the opening script tag to type="text/plain" with data-cq-category set to analytics or marketing.
Add the Cookie preferences link and testIn Structure, then Menus, add a link to #cq-preferences in the footer menu. Open the site in a private window, click Reject all and check that no _ga or _fbp cookie is set.

Where to paste the snippet in Drupal

Drupal prints every page through one template, html.html.twig, whose head holds three placeholders: one for head elements, one for CSS and one for JavaScript. The snippet should sit above all three, so it loads before any library or module script.

With a theme template (no module needed). Use a custom theme or a sub-theme of the theme you run. Copy the html.html.twig your theme inherits (Olivero ships its own in core/themes/olivero/templates/layout/; otherwise copy core/modules/system/templates/html.html.twig) into your theme's templates folder, and add the snippet on the line after <head>:

html
<head>
<script src="https://cookiequiet.com/cq.js" data-site="YOUR_SITE_KEY" data-consent-mode="1" data-auto-block="1" defer></script>
<head-placeholder token="{{ placeholder_token }}">
<title>{{ head_title|safe_join(' | ') }}</title>

Then clear the caches under Configuration, then Development, then Performance, or with drush cr. Drupal uses your copy of a template only after a cache rebuild. Do not edit Olivero or a contributed theme in place: the next update would remove the line.

With a custom module. If you would rather not touch templates, attach the tag from hook_page_attachments(). Elements added to html_head print in the head placeholder, before the CSS and JS:

php
function mymodule_page_attachments(array &$attachments) {
$attachments['#attached']['html_head'][] = [[
'#tag' => 'script',
'#attributes' => [
'src' => 'https://cookiequiet.com/cq.js',
'data-site' => 'YOUR_SITE_KEY',
'data-consent-mode' => '1',
'data-auto-block' => '1',
'defer' => TRUE,
],
], 'cookiequiet'];
}

The hook also runs on admin pages. That is harmless, but you can skip them by checking the router's admin context first.

Which cookies does Drupal set itself?

Drupal core sets one cookie of its own: the session cookie, named SESS (or SSESS on HTTPS) followed by a 32-character hash of the host. It is created when someone logs in, or when a module stores data in the session for an anonymous visitor (a cart, a form in progress). It is strictly necessary and needs no consent. Everything else comes from modules and the tags you add, which is why a scan matters more on Drupal than on most platforms: run the free cookie scanner on a few page types (home, article, form, shop) to see what your modules actually print.

How to handle the tags modules add

  • Google Tag module. It prints the Google tag for you, so you cannot mark it. In the tag container's advanced settings, tick Enforce Privacy Consent Policy: the module then sets Google's consent defaults to denied (ad_storage, analytics_storage, ad_user_data, ad_personalization) before it loads gtag.js. Cookiequiet sends the consent update command when the visitor chooses, which the tag applies whoever printed it. If you use Google Tag Manager instead, see the Google Tag Manager guide.
  • Tags you pasted. In a template or a block that uses the Full HTML text format, change the opening tag to <script type="text/plain" data-cq-category="marketing"> for the Meta Pixel, analytics for Hotjar or Clarity. The guide to blocking scripts until consent shows the pattern for inline and external scripts.
  • Scripts that modules inject with JavaScript. With data-auto-block="1", Cookiequiet holds the scripts and iframes of about 80 known trackers created this way until their category is granted.
  • Remote video. Drupal's Media module prints YouTube and Vimeo players as iframes in the HTML, so they load at once. For a video that must wait for consent, use an iframe with data-cq-src instead of src in a Full HTML block.

Uninstall any other consent module (EU Cookie Compliance, Klaro, COOKiES) after the switch, so visitors see one banner and one consent is recorded.

Go to Structure, then Menus, open the Footer menu and click Add link. Enter #cq-preferences as the link (Drupal accepts paths that start with a hash) and "Cookie preferences" as the title. Cookiequiet opens the preferences centre from any link with that address. If your footer is a custom block instead, add an anchor with the same href.

How to test

  1. Open the site in a private window, logged out. The banner shows with Accept all and Reject all of the same size.
  2. Click Reject all. In the developer tools (Application, then Cookies in Chrome) you should see cq_consent and nothing from Google, Meta or Hotjar.
  3. Clear the cookies, reload, click Accept all: the marked scripts run and their cookies appear.
  4. Check the consent log in the Cookiequiet dashboard.

If the banner does not show, view the page source and search for cq.js. A missing tag almost always means the cache was not rebuilt or the template sits in a theme that is not the default one.

What is specific to Drupal

  • Two themes. The admin theme (Claro) does not use your front-end template, so the banner appears only on the public site, which is what you want.
  • Page cache and reverse proxies. The snippet is the same for every visitor, so Drupal's page cache, Varnish or a CDN can cache pages that contain it. Purge them once after the change.
  • Multisite. Give each site its own site key so consent logs and policies stay separate.

Cookiequiet is free for one website with geo-targeting included, and Starter costs €3 per website per month with no pageview limit, see pricing.

Questions

No, and none is needed. The snippet is one script tag that goes in your theme's html.html.twig or is attached by a few lines of hook_page_attachments() in a custom module. Both print it in the head of every public page.
No. The SESS or SSESS cookie keeps a user logged in or holds a cart, which is strictly necessary for a service the visitor asked for. Drupal core only creates it when there is something to store in the session.
Tick Enforce Privacy Consent Policy in the tag container's advanced settings. The module then sets Google's consent defaults to denied before loading the tag, and Cookiequiet sends the update when the visitor accepts or rejects analytics and marketing.
Uninstall it after the switch. Two banners confuse visitors and record two different consents. Cookiequiet replaces its banner, its script blocking and its consent log.

Put a quiet banner on your website today

Free for one website with every core feature, no card and no trial clock. Upgrade a website to Starter for $3 a month to match your brand with AI and drop the branding, or to Pro for $9 to design it with the AI agent.