ConsentOverview

Consent Management

Signal provides comprehensive consent management that integrates with your Consent Management Platform (CMP), enforces consent rules per-integration before delivery, and passes the correct consent signals to each vendor API.

  1. Capture — Datafly.js reads consent state from your CMP’s cookie or storage location.
  2. Attach — Two views of the consent state are attached to every event payload:
    • context.consent.categories — the customer’s CMP-specific codes (e.g. statistics, C0002).
    • context.consent.canonical — Signal’s fixed vocabulary, mapped from those codes.
  3. Enforce — The pipeline engine filters integrations based on consent before delivery.
  4. Translate — Vendor blueprints reference consent through context.consent.canonical.<purpose>, so the same blueprint works for any CMP.
  5. Audit — Every filtering decision is logged.

The two views: categories vs canonical

Signal emits both views on every event so blueprints stay portable across CMPs:

{
  "context": {
    "consent": {
      "categories": {
        "necessary": true,
        "preferences": true,
        "statistics": false,
        "marketing": false
      },
      "canonical": {
        "essential": true,
        "functional": true,
        "analytics": false,
        "marketing": false
      }
    }
  }
}
ViewKeysUse it when
categoriesThe customer’s CMP codes verbatim (e.g. Cookiebot’s statistics, OneTrust’s C0002).Custom blueprints that intentionally tie to one CMP, or when surfacing the raw signal in audit/UI.
canonicalA fixed vocabulary of essential, functional, analytics, marketing, personalization.Vendor blueprints that ship with Signal. References stay valid no matter which CMP the customer uses.

See Canonical Categories for the full vocabulary, classification guidance, and migration notes.

Supported CMPs

Signal supports reading consent from any CMP, with first-class auto-seeding for the most common ones:

CMPCookie / StorageAuto-seeded categories
CookiebotCookieConsent (cookie)necessary, preferences, statistics, marketing
OneTrustOptanonConsent (cookie)C0001, C0002, C0003, C0004
Didomididomi_token (cookie)Configured per deployment
Osanoosano_consentmanager (cookie)Configured per deployment
IAB TCF v2.xeuconsent-v2 (cookie) or __tcfapiPer-vendor gating — see IAB TCF v2.x Support
CustomAny cookie or localStorage keyConfigured per deployment

When you select a known CMP in Settings → Consent, Signal pre-populates the standard categories and their canonical classifications. You can override these or add custom categories at any time.

Signal’s parser handles five formats so you rarely need transformation logic in your CMP integration:

  1. JSON object — {"necessary":true,"marketing":false}
  2. JS object literal (Cookiebot’s native shape) — {stamp:'abc==',necessary:true,...}
  3. Colon-delimited, comma-separated — essential:1,functional:1,analytics:0,marketing:0
  4. URL query string (OneTrust) — groups=C0001:1,C0002:1,C0003:0,C0004:0
  5. Semicolon-delimited key=value — analytics=1;marketing=0;functional=1

URL-encoding and double-encoding are handled transparently.

Consent enforcement happens at two stages:

  1. At ingestion — before any vendor-side identifier sync runs, Signal checks the visitor’s recorded consent against each sync’s required category (default marketing). Denied vendors are silently omitted so the browser never fires the corresponding match-pixel redirect. See Identity.
  2. At delivery — before events reach each vendor’s API. Each integration can have a consent category gate; events without the required consent are filtered and never delivered.

Both stages honour the pipeline’s consent_mode: explicit (GDPR, absent → denied) or implicit (CCPA, absent → granted).

Consent also gates the identity graph. A custom identity type can carry a consent category; events whose consent state does not grant it neither join nor extend the graph on that type — the check fails closed. For server sources that carry no consent state at all (POS, kiosk), a pipeline-level consent context can grant categories your legal basis covers — see Server & In-Store Sources. Explicit consent on an event is never overridden.

⚠️

Vendor-side identifier syncs trigger ePrivacy / PECR cookie-consent obligations even though Signal stores the resulting ID server-side. The browser → vendor redirect causes the vendor to read/write cookies on the vendor’s domain, which is exactly what ePrivacy regulates. Server-side storage location does not remove the consent requirement. The gating described above is on by default and should remain enabled for any pipeline handling UK/EU traffic.

Identifier cookies

The collection server sets first-party cookies on your domain, and consent decides how long they last:

  • Anonymous ID (_dfid) and device ID (_dfdid): persistent only when the visitor has granted a category that allows persistence (the pipeline’s Persist identifiers when consented to setting, or analytics/marketing when none is selected). Otherwise the anonymous ID is a session cookie and no device ID cookie is set. When the event carries no consent state at all (no consent provider configured), they persist. If your website sets the anonymous ID cookie itself (Using your own visitor ID), Signal never writes it, so when it is set and how long it lasts are your website’s decision.
  • Advertising click-ID cookies (_gcl_aw, _gcl_dc, _uetmsclkid, _li_fat_id, _scid, _epik): set only when persistence is allowed and marketing consent allows it. Marketing consent is read from canonical.marketing, then Google Consent Mode ad_storage, then a marketing category from the CMP. If the consent state says nothing about marketing, the pipeline’s consent_mode decides: explicit does not set them, implicit does. With no consent state at all, they are set. The click IDs themselves still travel on the event, and delivery applies each destination’s own consent gate.

Vendor blueprints reference consent through the canonical view:

# GA4 blueprint — works for Cookiebot, OneTrust, Didomi, anything
- target: "@root.consent.ad_user_data"
  source: "context.consent.canonical.marketing"
  transform:
    type: value_map
    map:
      "true": GRANTED
      "false": DENIED

The customer chooses how their CMP’s categories map to Signal’s canonical vocabulary in Settings → Consent. Once that mapping is set, every blueprint that references canonical.marketing (Meta CAPI, Google Ads, TikTok, GA4 …) reads the right value automatically.

Vendor-Specific Rules

In addition to the pipeline-level consent gate, each delivery layer applies vendor-specific consent enforcement. The blueprint determines the exact behaviour; the table below shows the typical defaults shipped with Signal:

VendorWhen canonical.marketing deniedAction
Meta CAPIdeniedStrip PII (email, phone, fbp, fbc, IP, UA). Set data_processing_options=['LDU'].
Google Adsany stateInclude Consent Mode v2 params. Google handles modelling internally.
GA4any stateInclude ad_user_data and ad_personalization in payload.
TikTokdeniedStrip PII (email, phone, ttp, ttclid, IP, UA). Set limited_data_use=true.
Microsoft UETdeniedSuppress event entirely (UET does not support degraded delivery).

IAB TCF v2.x Support

For publishers using the IAB Transparency & Consent Framework, Signal decodes the TC string and gates delivery per vendor — in addition to the category gating above. This is what TCF-native publishers (and their advertising partners) require: that a specific vendor had consent for specific purposes, and was disclosed in the CMP.

Because the TC string format and the IAB Global Vendor List (GVL) IDs are standardised, this works with any TCF-registered CMP — OneTrust, Cookiebot, Didomi, Sourcepoint, Usercentrics, Quantcast and others — with no per-CMP configuration. Only how the string is captured is configurable.

How it works

  1. Capture — Datafly.js obtains the TC string from the CMP’s __tcfapi API (authoritative — it also reports gdprApplies) or the euconsent-v2 cookie, and attaches it to every event as context.consent.tcf.tc_string.
  2. Decode — Signal decodes the TC string when it reaches your infrastructure: purpose consents, vendor consents, and the disclosed-vendors segment.
  3. Gate per vendor — each integration mapped to an IAB GVL vendor ID is delivered only when the user consented to that vendor, to all of its required purposes, and — when you require it — when the vendor was disclosed in the CMP.

When the CMP signals that GDPR does not apply (gdprApplies = false), TCF gating is skipped and events flow normally.

Configuring capture on the collector

Set the tcf block inside the collector’s consent config:

consent: {
  // … your category configuration …
  tcf: {
    enabled: true,
    source: 'auto',            // 'auto' (tcfapi → cookie), 'tcfapi', 'cookie', or 'param'
    cookieName: 'euconsent-v2' // override only if your CMP uses a non-standard name
  }
}
  • source: 'auto' (recommended) prefers the live __tcfapi value and falls back to the cookie.
  • source: 'param' is for server-side container setups where the TC string is forwarded to the collector rather than read from the page.

Pipeline-level options

  • Enable TCF gating on the pipeline to turn on per-vendor enforcement.
  • Require disclosed vendors (optional) — only deliver to a vendor when it appeared in the CMP’s disclosed-vendors list. Some publishers require this to prove the vendor was surfaced to the user.

Each integration’s IAB vendor ID and required purposes come from its integration blueprint, so you do not set them per deployment.

TCF gating runs in addition to the canonical category gate — an integration must satisfy both. A pipeline with no TCF configuration is unaffected and continues to use category gating only.

Every consent filtering decision is counted, per minute, in the consent_filtered_counts table:

FieldDescription
org_idThe organisation
pipeline_idWhich pipeline the event was processed through
integration_idWhich integration was blocked
consent_categoryThe consent category that was denied
event_typeThe type of event (page, track, etc.)
minuteStart of the UTC minute the decisions were made in
countHow many deliveries were withheld in that minute

Counts are kept for 90 days (CONSENT_FILTERED_COUNTS_RETENTION_DAYS) and hold no identifiers. Per event name counts are also in the Observe dashboards, which read the consent_filtered status of the event statistics.

⚠️

Before this release every decision was a row in consent_filtered_events (with the event name and a hash of the anonymous ID). That table is deprecated: it is no longer written, existing rows are kept, and it will be removed in a later release. If you query it directly, move to consent_filtered_counts. CONSENT_AUDIT_PER_EVENT_ROWS=true on the event processor restores the per-event rows until the table is removed; it adds one database write per withheld delivery, so it is not recommended at volume.

Configuration

  1. Go to Settings → Consent.
  2. Click Add Provider and pick your CMP (or Custom).
  3. Cookie name, storage type, and standard categories are pre-populated for known CMPs.
  4. Each category has a Canonical Category dropdown — set it to one of essential, functional, analytics, marketing, personalization. Leave blank for unclassified categories (they still appear under categories but not under canonical).

2. Choose the category each integration needs

Your consent banner records the visitor’s choice for each of your categories. Signal applies that choice to every integration: an integration receives an event only when the visitor’s consent allows its category.

  1. Go to Pipelines → [Your Pipeline] → Consent.
  2. Under Consent Category per Integration, choose one of your banner’s categories for each integration. When you add an advertising or analytics integration, Signal pre-selects your category classified as marketing or analytics, if you have exactly one. You can change it.
  3. Choose No consent needed only for an integration that is strictly necessary. It then receives every event.

An integration that shows No consent check was set up before this setting existed and receives every event, whatever the visitor chose. Choose a category for it.

3. Decide what applies before the visitor chooses

Until the visitor makes a choice in your banner, each category follows the setting you choose for it under Consent Categories → Before the visitor chooses:

  • Allowed: for example, first-party analytics that your banner keeps on until the visitor objects;
  • Not allowed: for example, marketing where consent must be given first;
  • Consent mode (the default): the pipeline’s Consent Mode, where Explicit means not allowed and Implicit means allowed.

Categories classified as essential are allowed before the visitor chooses. Once the visitor chooses, their choice wins, and a refusal stops delivery immediately, even for a category classified as essential, so classify as essential only what your banner cannot switch off.

Signal has no built-in rules for particular countries. If your banner applies different defaults by region, Signal follows whatever it stores for each visitor; these settings only apply while it has stored nothing. The settings take effect on the server, so changing them never needs a new tag.

Whenever the user updates consent (CMP banner, preferences page), call:

datafly.refreshConsent();

This is cheap and idempotent. The next event the SDK sends carries the new state. If your page saves a new choice without this call, the SDK notices it before the next event it sends.

Calls Datafly.js makes to third parties from the browser (the GA4 session beacon, ID syncs, match pixels, the cross-domain hub) wait for the visitor’s consent to their purpose: see Calls Datafly.js makes to other companies.