Add a cookie consent banner to a Drupal site

Cookbook · platform Last verified View raw markdown (for agents)

In short: paste the live snippet as the first thing in the <head> of your theme's html.html.twig. Or attach it from a small module with hook_page_attachments() and give the banner library a low weight.

Confirmed on a Drupal site: the snippet is the first script in the rendered page's <head>, on the front page and on an inner page.

You need #

Where it goes #

Option A: the theme template #

  1. Copy the live snippet (see above).

  2. In your custom theme, use templates/html.html.twig (copy the one from the theme you extend, for example core/themes/olivero/templates/layout/html.html.twig, if your theme does not have it yet).

  3. Paste the snippet as the first thing in <head>, above <head-placeholder>:

    <head>
      {# Cookie Compliance: first script on the page (paste live snippet here) #}
      <script>
          var huOptions = { "appID": "YOUR_APP_ID", "currentLanguage": "en", "blocking": true, "globalCookie": false };
      </script>
      <script src="https://cdn.hu-manity.co/v2/hu-banner.min.js" type="text/javascript" charset="utf-8"></script>
    
      <head-placeholder token="{{ placeholder_token }}">
      <title>{{ head_title|safe_join(' | ') }}</title>
      <css-placeholder token="{{ placeholder_token }}">
      <js-placeholder token="{{ placeholder_token }}">
    </head>
    
  4. Clear caches (Configuration → Development → Performance → Clear all caches) so Drupal rebuilds the Twig template. Your analytics libraries and tags stay as they are, below the snippet.

Option B: a module #

Use this when you would rather not carry a template override. In a custom module (modules/custom/my_banner/, with its usual my_banner.info.yml), put the options script in html_head and the library in the header scope with a low weight:

my_banner.libraries.yml

banner:
  header: true
  js:
    'https://cdn.hu-manity.co/v2/hu-banner.min.js': { type: external, weight: -100, attributes: { type: 'text/javascript', charset: 'utf-8' } }

my_banner.module

function my_banner_page_attachments(array &$attachments) {
  $attachments['#attached']['html_head'][] = [
    ['#tag' => 'script', '#value' => 'var huOptions = { "appID": "YOUR_APP_ID", "currentLanguage": "en", "blocking": true, "globalCookie": false };'],
    'my_banner_options',
  ];
  $attachments['#attached']['library'][] = 'my_banner/banner';
}

Enable the module and clear caches. Drupal writes html_head items before the stylesheets and the header libraries after them, so the options script comes first and the library follows ahead of your analytics libraries.

Header libraries are written in weight order. If an analytics module declares a low weight for its own library, give the banner library a lower one (the -100 above) so it stays first.

Custom blocks and other content regions write into the page body. For the banner, use the theme template or the module above.

What the order controls #

The banner holds recognised trackers that load after it until the visitor chooses, in regions whose rule requires consent first. A script placed above the snippet runs straight away, and a script you mark data-hu-category="1" is treated as essential. What runs before consent is your decision, so keep analytics and pixels below the snippet.

Confirm the result #

Clear caches, then view the page source of your front page and of one inner page (not the browser's Elements panel): the huOptions script and hu-banner.min.js are the first two <script> tags in <head> (with Option B the options script is right after the charset tag and the library follows the stylesheets), with no async or defer, and your analytics tag comes after them.

Then run the browser checks in plain-html in a private window (banner shows, no tracking cookies before the visitor chooses in a region whose rule requires consent first, trackers start after Allow) and, for the full procedure, verify-install. Test from a region your strictest rule covers (for example the EU), or confirm region rules are off.

Gotchas #

More help #