Canonical Categories
Signal defines a fixed, CMP-agnostic vocabulary for consent purposes. Customers map their CMP’s category codes (Cookiebot’s statistics, OneTrust’s C0002, custom codes, etc.) onto this vocabulary once in Settings → Consent, and every vendor blueprint can then reference consent without knowing anything about the customer’s CMP.
The vocabulary
| Canonical | Purpose | Typical CMP codes |
|---|---|---|
essential | Strictly necessary cookies and processing — site cannot function without them. Always granted. | Cookiebot necessary, OneTrust C0001, IAB Purpose 1 |
functional | Preferences, language, UI settings, non-essential personalisation of the site itself. | Cookiebot preferences, OneTrust C0003, IAB Purpose 5 |
analytics | Aggregate usage measurement, performance monitoring, A/B test enrolment. | Cookiebot statistics, OneTrust C0002, IAB Purpose 8/9 |
marketing | Advertising, retargeting, conversion tracking, audience building, server-side ad delivery (CAPI). | Cookiebot marketing, OneTrust C0004, IAB Purpose 2/3/4/7 |
personalization | Cross-property profile building, recommender systems, personalised content driven by user-level data. | Often folded into marketing by CMPs; split out where the customer wants finer control. |
The vocabulary is intentionally narrow. If your CMP uses 12 categories, you’ll map several of them onto the same canonical bucket (e.g. Cookiebot’s marketing and a custom social_marketing both → marketing). Signal OR-merges shared buckets — marketing: true if the user granted consent in any mapped category.
How it appears on events
Every event the SDK emits carries both views:
{
"context": {
"consent": {
"categories": {
"necessary": true,
"preferences": true,
"statistics": false,
"marketing": false
},
"canonical": {
"essential": true,
"functional": true,
"analytics": false,
"marketing": false
}
}
}
}categoriesis keyed by your CMP’s codes verbatim — useful for audit, custom blueprints, and when you intentionally want CMP-specific behaviour.canonicalis keyed by the vocabulary above — the recommended source for vendor blueprints.
If no categories in your provider have a canonical classification, canonical is omitted entirely and only categories is emitted. This is the back-compat shape — older blueprints that reference context.consent.categories.marketing keep working.
Referencing canonical from a blueprint
# GA4 — works for any CMP once the customer maps their categories
- target: "@root.consent.ad_user_data"
source: "context.consent.canonical.marketing"
transform:
type: value_map
map:
"true": GRANTED
"false": DENIED
- target: "@root.consent.ad_personalization"
source: "context.consent.canonical.marketing"
transform:
type: value_map
map:
"true": GRANTED
"false": DENIED# Meta CAPI — gate PII fields on canonical.marketing
- target: "user_data.em"
source: "user.email_sha256"
condition:
field: "context.consent.canonical.marketing"
equals: trueClassifying CMP categories
When you add a consent provider in Settings → Consent, each category row has a Canonical Category dropdown:
- Pick the canonical bucket that best matches the category’s purpose.
- For known CMPs (Cookiebot, OneTrust) Signal pre-fills the standard mapping — adjust only if your deployment differs.
- Leave the dropdown blank for categories you don’t want surfaced canonically (they still appear under
categoriesso custom blueprints can read them).
Mapping examples
Cookiebot (auto-seeded)
| Cookiebot code | Canonical |
|---|---|
necessary | essential |
preferences | functional |
statistics | analytics |
marketing | marketing |
OneTrust (auto-seeded)
| OneTrust group | Canonical |
|---|---|
C0001 | essential |
C0002 | analytics |
C0003 | functional |
C0004 | marketing |
Custom CMP with split marketing
| Custom code | Canonical |
|---|---|
essential | essential |
analytics_aggregate | analytics |
ads_targeting | marketing |
social_marketing | marketing |
recommender_profiling | personalization |
canonical.marketing becomes true if either ads_targeting or social_marketing is granted. The OR-merge matches “user gave consent for this purpose somewhere.”
Migration notes
From legacy consent shape
Earlier versions of the SDK emitted a flat context.consent shape:
{ "context": { "consent": { "analytics": true, "marketing": false } } }Current SDK builds emit the nested categories + canonical shape. Blueprints that referenced the old flat path should migrate to the canonical path:
| Old path | New path |
|---|---|
context.consent.analytics | context.consent.canonical.analytics |
context.consent.marketing | context.consent.canonical.marketing |
context.consent.functional | context.consent.canonical.functional |
From CMP-specific blueprints
Older blueprints that hardcoded a CMP’s vocabulary (e.g. context.consent.categories.statistics for Cookiebot) should switch to context.consent.canonical.<purpose>. Once the customer classifies their categories, the blueprint becomes portable across CMPs.
Roll-out order
When upgrading from CMP-specific to canonical refs:
- Deploy the SDK first —
categoriesandcanonicalare emitted side-by-side, so old and new blueprints both work. - Classify categories in Settings → Consent — until categories are classified,
canonicalis empty and canonical-aware blueprints will see all-false. - Bump the blueprint version — switch
sourcepaths tocontext.consent.canonical.*and ship as a new revision. - Upgrade attached integrations — pipelines pin to a specific revision; update each pipeline’s integration to the new revision when ready.
Related
- Consent overview — CMP integration, enforcement, audit logging.
- Identity — canonical consent gates vendor identifier syncs.