---
title: "Categories and purposes"
description: "How consent categories, services, and US opt-out purposes are modeled, and what each visitor action records."
url: "https://cookiebeam.com/docs/configure/categories-and-purposes"
lang: "en"
---

# Categories and purposes

How consent categories, services, and US opt-out purposes are modeled, and what each visitor action records.

CookieBeam organizes everything a visitor can consent to into **categories**. Categories are the unit the banner displays, the unit the blocking engine enforces, and the unit stored on the consent record.

## The category model

Your banner configuration defines a set of categories. Each category carries an `enabled` flag and can be marked `readOnly`:

- A `readOnly` category is always on. It appears in the preference panel but cannot be toggled off, and it is included in every recorded choice — including "accept necessary" and any custom selection. Strictly necessary storage belongs here.
- Every other category is optional. The visitor can grant or deny it, and in opt-out mode categories with `enabled: true` are pre-selected until the visitor says otherwise.

The scanner classifies what it finds into `necessary`, `analytics`, `marketing`, `preferences`, or `unknown` (see [Auto-scanner](https://cookiebeam.com/docs/configure/scanner)). You shape the banner's category list yourself in the designer's **Categories** section (**Dashboard → Banners → your banner → Design**); the inventory informs that work but does not write it.

Within a category you can also record consent at **service** granularity. The stored consent state keeps a map of category names to the individual services the visitor selected, so "analytics on, but only for these vendors" is representable.

## What each visitor action records

Every choice resolves to a category set and an `acceptType`:

| Action | Categories recorded | `acceptType` |
| --- | --- | --- |
| Accept all | Every category in the configuration | `all` |
| Accept necessary | Only the `readOnly` categories | `necessary` |
| Save custom selection | `readOnly` categories plus the visitor's selection | `custom` |

A custom selection always keeps the `readOnly` categories, and category names that no longer exist in the configuration are dropped rather than stored.

## The stored consent record

Each visitor's state is stored as a canonical record (schema version 2) containing the accepted categories and services, the `acceptType`, a unique consent ID, first and most recent consent timestamps, the banner language, and a configuration `revision` so you can prove which banner version the visitor saw. The schema also defines an optional `jurisdictions` field, but the browser runtime does not populate it — a record written by the banner does not tell you which regional rule matched, so do not rely on the field being present.

The record also carries provenance flags your auditors will ask about:

- `collectedVia` — how the row was produced: an explicit banner or preferences choice, the API, or a machine-written default (`default_optin`, `default_optout`, `default_notice`, `hidden_autogrant`).
- `isDefaultState` — the record is a machine-written default, not an explicit visitor choice.
- `isPending` — an opt-in visitor has not decided yet; nothing non-necessary is granted.
- `gpcRespected` — a privacy signal shaped this record (see [Privacy signals](https://cookiebeam.com/docs/configure/privacy-signals)).

## US opt-out purposes

For visitors under US opt-out frameworks, the preferences panel exposes per-purpose choices: **sale or sharing of personal data**, **targeted advertising**, and **sensitive data** (the data model also reserves `profiling`). These are recorded as `purposeChoices` on the consent log, distinct from the category list.

`purposeChoices` is populated only when a US visitor actively opens the opt-out panel and confirms it. It is deliberately `null` for:

- machine-written default records (auto-grants in opt-out or notice mode), and
- visitors under opt-in frameworks such as the GDPR presets, who never see the panel.

A `null` value on those rows is expected behavior, not missing data.

Note what analytics does with this: the dashboard's purpose opt-in/opt-out view aggregates the **consent categories** (`analytics`, `marketing`, `preferences`) stored in `consent_given`. It does not aggregate the US `purposeChoices` field, so per-purpose opt-out rates for sale/sharing, targeted advertising, and sensitive data are not reported there today — the stored `purposeChoices` rows are available in the consent log data itself.

## Publish and verify category changes

1. Edit the banner's **Categories** section and click **Save** in the designer.
2. Click **Publish** in the banner header and complete the publish dialog.
3. Open the served banner in a clean browser profile. Open its preferences panel and confirm the expected categories, services, and locked `readOnly` choices.
4. Save a custom selection and verify that the stored consent state contains the expected category and service selections.
