---
title: Configuration
description: Every option you can pass to the c15t script tag on a plain HTML
  page through a queued config call, including scripts with callbacks, the
  network blocker, theme tokens, presentation, translations and storage.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Pass options before the tag

Attributes on the script tag cover the common options. For everything else,
queue a `config` call in an inline script before the tag:

```html
<script>
  window.c15t = window.c15t || [];
  c15t.push(['config', {
    legalLinks: { privacyPolicy: { href: '/privacy' } },
    ui: { banner: { legalLinks: ['privacyPolicy'] } },
    reloadOnConsentRevoked: true,
  }]);
</script>
<script
  src="https://your-project.inth.app/c15t.js"
  defer
></script>
```

The tag has `defer`, so an inline script anywhere in `<head>` runs before it.
Later `config` calls win over earlier ones, and all of them win over the tag's
attributes. `ui`, `ui.banner` and `ui.dialog` merge key by key; other options
replace the earlier value. A `config` call after the client started does
nothing and logs a warning. [window.c15t API](/docs/frameworks/html/api#how-options-merge)
explains the order.

A `config` object can hold functions, such as script callbacks, because it
never leaves the page.

## Connection and policy

The `init()` and `createConsentClient()` of the `@c15t/browser` ES module,
`@c15t/browser/headless` and `@c15t/browser/iab` take `mode` as a factory
and none of the connection options below it. The script-tag builds and the
`@c15t/browser/hosted` and `@c15t/browser/offline` entries take the rest of
the table: `c15t.js` and `@c15t/browser/hosted` accept hosted mode only and
require a backend URL or hosted factory, and `c15t.offline.js` and
`@c15t/browser/offline` accept offline mode only.

|Option|Type|Default|What it does|
|--|--|--|--|
|`mode`|A transport factory. Script-tag builds also take `'hosted'`, `'offline'` or `'manifest'`.|Required in the ES modules. Script-tag builds pick it from the other options.|A factory from `manifest()`, `hosted()`, `offline()` or `custom()` is used as is; see [consent modes](/docs/concepts/modes). In the script-tag builds, `manifest` when `manifest` or `manifestURL` is set, `hosted` when `backendURL` is set, otherwise `offline`. Hosted mode without `backendURL` throws.|
|`backendURL`|`string`|none|Script-tag builds, `/hosted` and `/offline` entries. Your Inth or self-hosted backend URL, for hosted and manifest modes. In the ES modules, pass it to the factory, such as `hosted({ backendURL })`.|
|`manifest`|`ConsentManifest`|none|Script-tag builds. The backend's policy manifest, inlined in the page, for manifest mode. In the ES modules, `manifest({ snapshot })`.|
|`manifestURL`|`string`|none|Script-tag builds. Where manifest mode fetches the manifest. A URL that ends in `/manifest` also gives the backend URL; any other URL needs `backendURL` too. In the ES modules, `manifest({ manifestURL })`.|
|`policyRules`|array of policy rules or preset names|recommended rules|Script-tag builds and the `/hosted` and `/offline` entries. Offline mode only. A preset name such as `'europeOptIn'` stands for that preset in `policyRulePresets`. An unknown name throws. In the ES modules, `offline({ policyRules })` with rule objects.|
|`overrides`|`{ country?, region?, language?, gpc? }`|none|The visitor's location, language or GPC signal, when the page knows it. Policy matching uses these instead of detection.|
|`prefetch`|kernel configuration|none|A server-resolved init answer. When it carries a resolved policy, the client renders from it and does not call `/init`.|
|`enabled`|`boolean`|`true`|`false` grants every category, shows no UI and loads every configured script at once.|

The [attributes reference](/docs/frameworks/html/attributes-and-api#choose-a-mode)
compares the modes and their bundle files.

## Scripts, blockers and data

|Option|Type|Default|What it does|
|--|--|--|--|
|`scripts`|`Script[]`|`[]`|Vendor scripts to load once their category is allowed. Each entry needs `id`, `category`, and `src` or `textContent`.|
|`consentCategories`|category names|categories your scripts, iframes and rules use|The categories the preference dialog offers, within the policy's scope. `necessary` is always included.|
|`networkBlocker`|`{ rules, enabled?, logBlockedRequests?, onRequestBlocked? }` or `false`|off|Hold `fetch` and `XMLHttpRequest` calls that match a rule until the rule's category is allowed.|
|`iframeBlocker`|`{ disableAutomaticBlocking? }` or `false`|on|Gate iframes that carry `data-category` or `data-vendor`. `false` turns it off. With `disableAutomaticBlocking: true`, c15t checks iframes only when you call `processIframes()`.|
|`nonce`|`string`|none|Content Security Policy nonce for the stock UI's `<style>` element and every `<script>` the `scripts` option loads. A script's own `nonce` wins. With a nonce set, c15t runs only the `<script type="text/plain" data-c15t-category>` tags that carry the same `nonce`.|
|`scriptLoader`|`{ onDebug? }`|none|`onDebug` receives every script loader lifecycle event.|
|`vendors`|`Vendor[]`|none|Vendors offered for vendor-level consent outside IAB. The preference dialog lists a switch for each. They merge with vendors from the backend, `vendor` fields on scripts and rules, and `data-c15t-vendor` on gated tags.|
|`clearOnRevocation`|cookies and storage keys per category|off|Delete named cookies and storage keys when their category is denied. Read once, at start.|
|`reloadOnConsentRevoked`|`boolean`|`true`|Reload the page after an accept, reject or save turns off a category that was allowed, once the save request finishes.|
|`callbacks`|`{ onChoiceRecorded?, onPermissionsChanged?, onError?, onBeforeConsentRevocationReload? }`|none|Functions c15t calls on consent events.|
|`storageConfig`|`{ storageKey?, crossSubdomain?, defaultDomain?, defaultExpiryDays? }`|key `c15t`, current host, 365 days|The name, domain and lifetime of the consent cookie and localStorage key.|
|`persistence`|`boolean` or `{ storageConfig?, skipHydration?, sync? }`|`true`|Read and write choices in the cookie and localStorage, and follow other tabs. `false` keeps choices in memory only. `{ sync: false }` stops following other tabs.|
|`user`|`{ externalId, identityProvider?, identityToken?, externalIdType?, properties? }`|none|An identified visitor, sent with consent records. [`identityToken`](/docs/self-host/api/node-sdk#verify-a-link-made-in-the-browser) verifies the link. Links only a subject the next save creates; use `identify()` for an existing one.|
|`iab`|IAB options or `false`|none|CMP settings such as `cmpId` and `vendors`. Only the IAB build accepts it; the other builds throw when it is set.|

Each of these has a guide: [scripts](/docs/frameworks/html/scripts),
[embeds](/docs/frameworks/html/embeds),
[network blocker](/docs/frameworks/html/network-blocker) and
[events and callbacks](/docs/frameworks/html/callbacks).

## Presentation and copy

|Option|Type|Default|What it does|
|--|--|--|--|
|`ui`|UI options or `false`|stock UI on|Theme tokens, CSS, surfaces and mounting. `false` starts the client with no UI. See [UI options](#ui-options).|
|`presentation`|`{ prompt?, preferences? }`|floating banner, bottom left|Banner shape, position, button layout and blocking, within what the policy allows.|
|`i18n`|`{ locale?, messages }`|English|The language to start in, and messages per language that override the bundled, backend or manifest copy key by key for that language.|
|`legalLinks`|`{ privacyPolicy?, cookiePolicy?, termsOfService? }`|none|Each link is `{ href, label?, target?, rel? }`. The banner and dialog show only the links their `legalLinks` option lists.|

## UI options

These go under `ui`. The headless builds ignore them.

|Option|Type|Default|What it does|
|--|--|--|--|
|`theme`|theme tokens|none|Colors, radius, typography, spacing and motion. The same token object every c15t package takes.|
|`css`|`string`|none|CSS added after the bundled stylesheet, in the same root as the UI.|
|`colorScheme`|`'light'`, `'dark'` or `'system'`|`'system'`|Which token set to use. `system` follows the visitor's setting and updates when it changes.|
|`shadow`|`boolean`|`true`|Render inside a shadow root. `false` renders into the page, where your stylesheet applies.|
|`styles`|`boolean`|`true`|Include the bundled stylesheet. Set `false` with `shadow: false` when the page loads the stylesheet itself.|
|`noStyle`|`boolean`|`false`|Render markup with no c15t classes and no bundled stylesheet, for fully custom CSS. `theme` and `css` still apply.|
|`disableAnimation`|`boolean`|the visitor's reduced motion setting|Show and hide surfaces without transitions.|
|`container`|element or CSS selector|`document.body`|Where the UI host element is appended. A selector that matches nothing throws.|
|`banner`|`boolean` or banner options|`true`|`false` renders no banner. An object sets copy and behavior; see the banner options.|
|`dialog`|`boolean` or dialog options|`true`|`false` renders no preference dialog.|
|`trigger`|`boolean` or trigger options|`false`|Render the floating button that reopens the dialog.|
|`iab`|`{ loadErrorText?, saveErrorText?, moreVendorsText? }`|translated copy|Copy for the IAB vendor list states. IAB build only.|

The banner, dialog and trigger options are on their component pages:
[banner](/docs/frameworks/html/components/banner),
[preference dialog](/docs/frameworks/html/components/dialog) and
[floating trigger](/docs/frameworks/html/components/trigger).

## Which attribute sets which option

|Attribute|Option|
|--|--|
|`data-backend-url`|`backendURL`|
|`data-mode`|`mode`|
|`data-manifest-url`|`manifestURL`|
|`data-policy-rules`|`policyRules`|
|`data-categories`|`consentCategories`|
|`data-country`, `data-region`, `data-language`|`overrides.country`, `overrides.region`, `overrides.language`|
|`data-privacy-policy-url`, `data-cookie-policy-url`, `data-terms-url`|`legalLinks`, plus `ui.banner.legalLinks` and `ui.dialog.legalLinks`|
|`data-color-scheme`|`ui.colorScheme`|
|`data-trigger`|`ui.trigger: true`|
|`data-hide-branding`|`ui.banner.hideBranding` and `ui.dialog.hideBranding`|
|`data-shadow="false"`|`ui.shadow: false`|
|`data-no-ui`|`ui: false`|
|`data-nonce`, or the tag's own `nonce`|`nonce`|

## Store the consent cookie across subdomains

By default c15t stores choices in a cookie and a localStorage key named `c15t`
on the current host, for 365 days. To share one choice between
`www.example.com` and `shop.example.com`, set `storageConfig`:

```html
<script>
  window.c15t = window.c15t || [];
  c15t.push(['config', {
    storageConfig: { crossSubdomain: true, defaultExpiryDays: 180 },
  }]);
</script>
```

`crossSubdomain` sets the cookie on the root domain. `defaultDomain`, such as
`'.example.com'`, sets it explicitly and wins over `crossSubdomain`. Use the
same settings on every site that shares the cookie. localStorage stays per
host, so a tab on another subdomain picks up a change when it next becomes
visible. [Consent state](/docs/concepts/consent-state#keep-open-tabs-in-step)
explains the rules.

## Turn consent management off

`enabled: false` allows every category, shows no UI and loads every
configured script at once, as for a visitor who accepted everything. Use it
for internal preview builds, not for visitors a consent law covers.
