[Consent banner](/consent-banner)

# Add a cookie consent banner to any HTML site

One script tag adds the banner and the preference dialog to your site. It holds vendor tags until the visitor chooses, with nothing to install or build.

[Start for free](/dashboard/sign-up) · [See the code](#install)

Ask your coding agent: `Add inth to my app: inth.com/SKILL.md`

- **Framework**: Any HTML site, CMS or static site generator
- **Library**: @c15t/browser, open source
- **Code checked**: 28 October 2026

## Add the script tag

c15t is the open source consent library behind Inth Consent. Your Inth project serves it as one script tag, with your backend URL already set.

```html
<script
  src="https://your-project.inth.app/c15t.js"
  defer
></script>
```

Paste the tag into the `<head>` of every page. Replace `https://your-project.inth.app` with the URL from your Inth project, and keep `/c15t.js` at the end.

The tag goes in the shared `<head>` that every page renders.

Examples are the `header.php` file of a WordPress child theme and the head code setting in Webflow. Others are `layout/theme.liquid` in Shopify and the base layout of your static site generator. [Install on your platform](https://c15t.com/docs/frameworks/html/platforms) gives the exact place for each platform.

Code on this page comes from the [c15t HTML quickstart](https://c15t.com/docs/frameworks/html/quickstart), checked 28 October 2026.

## Hold scripts until consent

Change the `type` of each vendor tag to `text/plain` and name its category in `data-c15t-category`. The browser ignores a `text/plain` script, so the vendor stays off until c15t runs it.

```html
<!-- PostHog's snippet, saved as a file on your site -->
<script
  type="text/plain"
  data-c15t-category="measurement"
  src="/posthog.js"
></script>
```

Remove the original copy of each vendor tag, and the copies that a theme or plugin adds. Use `measurement` for analytics and `marketing` for ads and pixels. [HTML scripts](https://c15t.com/docs/frameworks/html/scripts) covers inline snippets and callbacks.

## Hold embeds until consent

Move the URL of an iframe from `src` to `data-src` and add `data-category`. c15t sets `src` after the visitor gives consent for that category.

```html
<iframe
  data-src="https://www.youtube-nocookie.com/embed/czTksCF6X8Y?playsinline=1"
  data-category="measurement"
  title="YouTube video"
  allow="encrypted-media; picture-in-picture"
  allowfullscreen
></iframe>
```

Without a `src`, the iframe loads nothing. [HTML embeds](https://c15t.com/docs/frameworks/html/embeds) has placeholder markup.

## Add a privacy settings link

Visitors need a way to change their choice after the banner closes. A link to `#c15t-preferences` opens the preference dialog, with no JavaScript on your page.

```html
<a href="#c15t-preferences">Privacy settings</a>
```

Put the link in the footer of every page.

## Google Consent Mode v2 on an HTML site

The script tag does not send Google Consent Mode signals. One option is to gate the Google snippet like any other vendor. Google then loads only after consent and sends nothing before a choice.

If you need Consent Mode, load the Google snippet ungated and send the signals yourself. Put this before the Google tags:

```html
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag() { dataLayer.push(arguments); }
  gtag('consent', 'default', {
    analytics_storage: 'denied',
    ad_storage: 'denied',
    ad_user_data: 'denied',
    ad_personalization: 'denied',
  });
  window.c15t = window.c15t || [];
  c15t.push(['on', 'consent', (snapshot) => {
    const allowed = snapshot.effectivePermissions;
    const state = (granted) => (granted ? 'granted' : 'denied');
    gtag('consent', 'update', {
      analytics_storage: state(allowed.measurement),
      ad_storage: state(allowed.marketing),
      ad_user_data: state(allowed.marketing),
      ad_personalization: state(allowed.marketing),
    });
  }]);
</script>
```

With Consent Mode, Google gets requests before a choice, marked as denied. Decide which behavior your policy needs before you pick one. [Read the developer guide to Consent Mode v2](/blog/developer-guide-to-consent-mode-v2).

## Show the right banner in each region

Your Inth project sets a policy for each region, such as opt in for the EU and UK or opt out for California. When the tag runs, `/init` returns the policy for that visitor. A visitor who already chose sees no banner.

Test each region before launch. [See how regional policies work](/consent-banner/regions).

## How the tag loads

With `defer`, the browser continues to parse the page while the script downloads. When it runs, the tag gets the policy for the visitor and then shows the banner if the policy asks for one. `c15t.js` leaves out the local policy presets and manifest code.

A page without the tag has no consent state. Check a few pages from different templates after you publish.

## Check that consent gates work

Open the site in a private window with the Network tab open. Test under an opt in policy, such as the EU policy.

1. Under an opt in policy, no PostHog request leaves the page before a choice.
2. After Reject All and a reload, PostHog stays off.
3. When you turn on measurement in Privacy settings, PostHog loads.
4. When you turn measurement off, the page reloads without PostHog.

Choices post to your Inth project. Check that Inth has a record for each one. The [c15t verify consent guide](https://c15t.com/docs/guides/verify-consent) has the full release checklist.

## Use Inth in production

c15t is open source. Point it at your Inth project, which hosts the backend and keeps the consent records. [See Inth open source](/oss).

c15t also has a local mode with no backend. It keeps no consent records, so the docs advise against it in production.

Want to see what else your site sends before consent? [Run a free codebase scan](/run-free-codebase-scan).

## Cookie consent banners for other frameworks

The same banner and the same Inth project work in other stacks. See the setup for [Next.js](/consent-banner/nextjs), [React](/consent-banner/react), [TanStack Start](/consent-banner/tanstack-start), [Nuxt](/consent-banner/nuxt), [Vue](/consent-banner/vue), [Astro](/consent-banner/astro), [Svelte](/consent-banner/svelte), [SvelteKit](/consent-banner/sveltekit) and [JavaScript](/consent-banner/javascript).

Do you use a bundler? See the [JavaScript cookie consent banner](/consent-banner/javascript).

[See how the Inth consent banner works](/consent-banner).

## Questions about HTML consent

### Do I need a build step?

No. Paste one script tag into the `<head>` of every page. There is nothing to install.

### Does it work with WordPress, Webflow or Shopify?

Yes. Put the tag in the shared `<head>` of your theme or site settings. [Install on your platform](https://c15t.com/docs/frameworks/html/platforms) gives the exact place.

### How do I stop analytics before consent?

Change the vendor tag to `type="text/plain"` and add `data-c15t-category`. Remove the original copy.

### Does the script tag send Google Consent Mode signals?

No. Gate the Google snippet, or load it ungated and send the signals yourself with the code on this page.

### How do visitors change their choice later?

Add a link to `#c15t-preferences`. It opens the preference dialog.

### Does it show a different banner in each region?

Yes. Set a policy for each region in your Inth project. c15t applies the policy that matches the visitor’s location. [See regional policies](/consent-banner/regions).

### Is c15t open source?

Yes. c15t is open source. Your Inth project hosts the backend and keeps the consent records.