---
title: Add Cookie Compliance to a plain HTML site
kind: platform
last_verified: 2026-09-28
---

# Add Cookie Compliance to a plain HTML site

**In short:** paste the **live** two-tag snippet (from MCP `install.getSnippet` or the dashboard Integrations page) as the **first thing inside `<head>`** on **every page**, above every other script. Leave your analytics tags where they are, below it.

## You need

- A Cookie Compliance **AppID**, for example `examplecom-1a2b3c4`. You'll find it in the Cookie Compliance dashboard. No account yet? Sign up; the free plan needs no card.
- Access to edit the HTML of every page, or the shared header file they all include.

## The wrong way

```html
<head>
  <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
  <script>/* gtag config */</script>

  <!-- banner added last, "so it doesn't slow the page down" -->
  <script async src="https://cdn.hu-manity.co/hu-banner.min.js"></script>
</head>
```

The banner shows up, but Google Analytics has **already run and set its cookies** before the visitor sees it. The consent is decoration. Three things are wrong here:

1. The snippet comes **after** a tracker. The widget can only block scripts that haven't run yet.
2. `async` lets the browser run it whenever it likes, so the order is lost.
3. The `huOptions` block is missing, so the widget doesn't know which app it belongs to.

## The right way

1. **Get the live snippet — do not rebuild it from memory.** Copy it from the dashboard (**Integrations → Manual Integration**), or ask an agent that has the Cookie Compliance MCP server connected to call `install.getSnippet` (also listed as `install_getSnippet`) with your AppID. Paste the returned HTML **unchanged**. That source already picks the correct script URL for your app's banner engine:
   - **v1** (default): `https://cdn.hu-manity.co/hu-banner.min.js`
   - **v2**: `https://cdn.hu-manity.co/v2/hu-banner.min.js`

   Shape (keys and URL vary — treat this as illustration only):

   ```html
   <script>
       var huOptions = {
           "appID": "YOUR_APP_ID",
           "currentLanguage": "en",
           "blocking": true,
           "globalCookie": false
       };
   </script>
   <script src="https://cdn.hu-manity.co/hu-banner.min.js" type="text/javascript" charset="utf-8"></script>
   ```

   If you later switch banner engine in the dashboard, **re-copy and replace** the snippet on every page. Changing the setting alone does not update a hand-pasted install.

2. **Put it first in `<head>`**, before anything else that runs code:

   ```html
   <head>
     <meta charset="utf-8">
     <!-- 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/hu-banner.min.js" type="text/javascript" charset="utf-8"></script>

     <!-- your existing tags stay here, unchanged -->
     <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
   </head>
   ```

3. **Repeat on every page.** If your pages share a header include, put it there once.

4. **Leave your trackers alone.** Don't delete them and don't wrap them in your own "if consented" code. The widget holds them back until the visitor agrees.

**Options in `huOptions` (common keys):**

| Key | Default | Change it when |
|---|---|---|
| `blocking` | `true` | Almost never. `false` means scripts run before consent. |
| `currentLanguage` | `"en"` | The page is in another language (two-letter code). |
| `globalCookie` | `false` | Consent should be shared across your subdomains. |

The dashboard snippet may also include other keys (for example Consent Mode defaults, `blockingEngine`, custom providers). Keep whatever the live snippet gave you.

Colours, wording, consent categories and regions are **not** set in the page. They live in your published configuration in the dashboard, and anything you add to the page for them is overwritten when the banner loads.

## Check it works

Use a **private window**, so no earlier consent is remembered.

**Your location matters.** If region rules are switched on in the dashboard, the banner and the blocking follow the rule for the visitor's region. Some regions may be set to show no banner, or not to block. Test from a location covered by your strictest rule (for example the EU), or confirm region rules are off, before judging checks 1 and 3.

| # | Check | Pass |
|---|---|---|
| 1 | **Look at the page** | The banner appears on first visit. There is **no** "Hu-manity PREVIEW — not active consent management" badge (that badge means a demo snippet was installed instead of the real one). |
| 2 | **View the page source** | The `huOptions` block and `hu-banner.min.js` are the first scripts in `<head>`, with no `async` or `defer`, and the page contains no `previewMode`. For a v2 app, the script `src` is `/v2/hu-banner.min.js`. |
| 3 | **Before clicking anything** | No tracking cookies (for example `_ga`, `_gcl_au`, `_fbp`) in the Application → Cookies panel, and no **data hits** in the Network tab (for example `google-analytics.com/g/collect`, `facebook.com/tr`). |
| 4 | **Allow everything** (choose the most permissive option, then save) | Trackers start running straight away, with no reload needed: their cookies appear and data hits go out. After a reload the banner stays closed and a `hu-consent` cookie exists. |
| 5 | **Another page** | Repeat checks 1–3 on an inner page, in a fresh private window, not only the homepage. |

Check 3 is the one that matters for compliance. In the Elements panel, blocked tags show `type="javascript/blocked"`, but cookies and data hits are the real proof, because a script can still inject other scripts.

**A tracker's script file may still download before consent.** While the page loads, the browser looks ahead in the HTML and starts downloading `<script src>` files it finds there, even while the Cookie Compliance snippet above them is still running. (Scripts that code adds later are not fetched this way.) So you can see a request for a file such as `googletagmanager.com/gtag/js` even when the banner is blocking it correctly: the file downloads but never runs. That is not a failure, as long as its cookies and data hits stay absent. To confirm it didn't run, type these in the browser console before choosing anything: `typeof google_tag_manager` should print `"undefined"` (Google), and `typeof fbq === 'undefined' || !fbq.getState` should print `true` (Meta).

**Google, Meta or Microsoft Consent Mode on?** Then their loader scripts (such as `googletagmanager.com/gtag/js` or `connect.facebook.net`) are **allowed to load before consent** on purpose. They receive a "denied" consent signal instead of being blocked. With Google Consent Mode, cookieless pings to `google-analytics.com` that carry the denied state are expected too. Seeing those requests is correct. Judge check 3 by the cookies: none of their tracking cookies should appear before the visitor accepts.

## Gotchas

- **Automated browsers see no banner.** The widget deliberately doesn't run when the browser reports that it is automated (`navigator.webdriver`), or when the user agent looks like a bot, including `HeadlessChrome`. If you check with Playwright, Puppeteer or Selenium, hide `navigator.webdriver` and use a normal desktop user agent, or you'll get a false "banner missing".
- **"Combine" or "minify JS" optimisers** (in hosting panels or caching plugins) can merge or move the snippet. Exclude both tags from them.
- **"Banner not showing" right after signup:** one common cause is a configuration that was saved but not **published** in the dashboard.
- **Wrong engine URL:** a v2 app with the v1 script path (or the reverse) after an engine switch — re-copy from Integrations / `install.getSnippet`.
- **Remove any other consent banner.** If the site already has a hand-made cookie popup or another consent tool, take it out. Two banners give visitors two conflicting choices.
- **Only install your own AppID.** Consent recorded by the snippet is logged against that app, together with the page address it came from.
