---
title: Consent categories
description: Assign scripts, embeds and features to c15t consent categories, and
  understand which categories the preference dialog shows.
group: concepts
lastModified: "2026-10-10T16:01:45+01:00"
---
## Choose categories by purpose

|Category|Purpose|
|--|--|
|`necessary`|Functionality required for the site to operate|
|`functionality`|Optional features such as support widgets|
|`measurement`|Analytics and usage measurement|
|`experience`|Optional personalization|
|`marketing`|Advertising and marketing|

`necessary` is always permitted. Assign categories based on what an integration
does in your application; renaming analytics to necessary does not change its
purpose.

c15t discovers categories from registered scripts, network rules, React `ConsentGate`
components, and iframes with `data-category` handled by the iframe blocker.
The browser client also discovers inert scripts tagged with `data-c15t-category`.
Compound script and network conditions contribute every category they reference.

Discovered categories are added to `consentCategories`, when supplied. The dialog
always includes Necessary and offers the optional categories in that combined
set that are also in the resolved policy scope. Choice completion uses the same
set.

If neither configuration nor integrations supply categories, the result depends
on the policy's `scopeMode`:

* Under a permissive policy, the dialog lists only Necessary. The banner still
  appears when the policy prompts for a choice. Accept All, Reject All and Save
  each record that the visitor saw it, send a consent receipt for Necessary
  alone in hosted and manifest modes, and keep the banner dismissed after
  reload. The acknowledgement expires with the policy's choice validity and
  after a policy change, like a choice would. A stored choice that is still
  valid under the current policy also counts as an acknowledgement.
* Under a strict policy, or an IAB TCF policy, the dialog uses the full policy
  scope. TCF consent is given per purpose and recorded in the TC string.

A category declared after that acknowledgement, such as a newly registered
script or a discovered iframe, needs a choice, so the banner asks again.

Categories discovered later are added immediately and retained until the provider
or runtime is recreated. Adding a category can require a new choice; removing a
script or unmounting a frame does not remove its category or erase consent.
Discovery does not grant consent or change backend permission restrictions.

## Respect policy scope

A strict scope denies categories outside the rule. A permissive scope can allow
out-of-scope categories unless another restriction applies. When a rule selects
only some optional categories, set `scopeMode` explicitly. An omitted scope,
`['*']`, or a list containing only `necessary` expands to the default optional
categories; a necessary-only list is not a shortcut for disabling all tracking.

For example, a backend rule with `categories: ['necessary']` and scripts assigned
to `marketing` and `measurement` displays Necessary, Marketing, and Analytics,
even without `consentCategories`. Accept All records both optional choices and
keeps the banner dismissed after reload. An explicit list of
`['necessary', 'measurement']` with no other integrations displays Necessary and
Analytics.

Hidden optional categories do not need a choice to dismiss the banner. Their
permissions still follow the backend policy, so hidden opt-in categories remain
denied without a valid grant. React providers enable DOM iframe blocking and
discovery by default. The blocker loads when the first iframe with
`data-category` or `data-vendor` is on the page, so pages without one never
download it; until it runs, such an iframe that arrives with a `src` consent
does not allow is paused. Write gated iframes with `data-src`, not `src`. The
browser requests a `src` as soon as the iframe is in the document, before the
blocker can pause it, whether the iframe comes from the server HTML or a
client render. Set
`iframeBlocker: false` to disable it, or
`iframeBlocker: { disableAutomaticBlocking: true }` to scan manually with
`useIframeBlocker({ disableAutomaticBlocking: true }).processAllIframes()`.

Use effective permissions to gate work and explicit choices to inspect what the
visitor confirmed. Read [how consent works](/docs/concepts/how-consent-works#a-permission-is-not-a-recorded-choice) for that
distinction and [policies](/docs/concepts/policies) for v3 policy configuration.
