Datafly.js SDKConsent Management

Consent Management

Datafly.js includes built-in consent management that integrates with popular Consent Management Platforms (CMPs). Consent state is read from the page automatically and used to gate both event collection (client-side) and event delivery (server-side).

Consent is enforced at two levels:

  1. Client-side (Datafly.js) — reads consent state from the CMP and includes it with every event. Client-side tag injection is gated by consent category.
  2. Server-side (Delivery Workers) — re-checks consent before delivering events to each vendor. Even if an event reaches the server, it will not be forwarded to a vendor unless the required consent category is granted.

This dual enforcement ensures that vendor data delivery respects user consent regardless of client-side manipulation.

User grants consent


┌──────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  Datafly.js  │────>│ Ingestion Gateway│────>│ Delivery Workers │
│  reads CMP   │     │  stores consent  │     │  re-checks       │
│  includes in │     │  with event      │     │  consent before   │
│  event       │     │                  │     │  vendor delivery  │
└──────────────┘     └──────────────────┘     └─────────────────┘

Datafly uses three consent categories that map to standard CMP groupings:

CategoryDescriptionExample vendors
analyticsPerformance and analytics cookies/trackingGoogle Analytics 4
marketingAdvertising and targetingMeta Pixel, TikTok, Pinterest, Snapchat
functionalFunctional and preference cookiesA/B testing tools, chat widgets

Strictly necessary cookies (like the _dfid identity cookie) do not require consent and are always set. They contain no tracking data — only an anonymous identifier needed for basic site functionality.

Supported CMPs

Datafly.js automatically detects and reads consent from the following CMPs. No additional configuration is required — just install your CMP as usual and Datafly.js will find it.

OneTrust

Datafly.js reads the OptanonConsent cookie and parses the consent groups:

OneTrust groupDatafly category
C0001 (Strictly Necessary)Always allowed
C0002 (Performance)analytics
C0003 (Functional)functional
C0004 (Targeting)marketing
OptanonConsent cookie value:
groups=C0001%3A1%2CC0002%3A1%2CC0003%3A0%2CC0004%3A0

Parsed as:
  C0001: 1 (Necessary - always on)
  C0002: 1 (Analytics - granted)
  C0003: 0 (Functional - denied)
  C0004: 0 (Marketing - denied)

Cookiebot

Datafly.js reads the CookieConsent cookie and maps the Cookiebot fields:

Cookiebot fieldDatafly category
necessaryAlways allowed
statisticsanalytics
preferencesfunctional
marketingmarketing

If you manage consent yourself or use a CMP not listed above, Datafly.js reads a _df_consent cookie with a simple key-value format:

_df_consent=analytics=1;marketing=0;functional=1

Values of 1 or true indicate consent granted. Values of 0 or false indicate consent denied.

Configuration

Configure the default consent state (before the user makes a choice) in your source configuration:

{
  "consent": {
    "mode": "onetrust",
    "default_state": {
      "analytics": false,
      "marketing": false,
      "functional": false
    }
  }
}

The mode option tells Datafly.js which CMP to look for first. Supported values:

ModeCMPCookie read
"onetrust"OneTrustOptanonConsent
"cookiebot"CookiebotCookieConsent
"custom"Your own CMP_df_consent
"auto" (default)Auto-detectChecks all in order

Opt-in vs opt-out regions

For regions where consent is not required (e.g., United States under current law), you can set defaults to true:

{
  "consent": {
    "mode": "auto",
    "default_state": {
      "analytics": true,
      "marketing": true,
      "functional": true
    }
  }
}
⚠️

Consent defaults should match your legal obligations. Setting defaults to true means events will be collected and delivered before the user interacts with a consent banner. Consult your legal team for the correct default state for each region you operate in.

If your CMP is not auto-detected, set the _df_consent cookie from your consent handler:

// Example: integrating with a custom consent banner
consentBanner.onAccept((categories) => {
  const parts = [];
  if (categories.analytics) parts.push('analytics=1');
  if (categories.marketing) parts.push('marketing=1');
  if (categories.functional) parts.push('functional=1');
 
  document.cookie = `_df_consent=${parts.join(';')};path=/;max-age=31536000`;
});
 
consentBanner.onReject(() => {
  document.cookie = '_df_consent=analytics=0;marketing=0;functional=0;path=/;max-age=31536000';
});

You can read the current consent state from Datafly.js at any time:

const consent = _df.getConsent();
console.log(consent);
// { analytics: true, marketing: false, functional: true }

This is useful for conditionally showing UI elements or gating your own application features based on consent.

If you use Datafly’s client-side tag injection (for tags that must run in the browser), tags are consent-gated by category. A tag will only be injected if the user has granted consent for its category:

_df.injectTag({
  id: 'hotjar',
  src: 'https://static.hotjar.com/c/hotjar-123456.js',
  consentCategory: 'analytics',
  timing: 'post-render',
});
// This tag will only load if consent.analytics === true

Consent is re-checked at the time of injection. If a user revokes consent, subsequently scheduled tags will not be injected.

The current consent state is sent with every event, allowing the server to make delivery decisions:

{
  "type": "track",
  "event": "Product Viewed",
  "context": {
    "consent": {
      "analytics": true,
      "marketing": false,
      "functional": true
    }
  }
}

The server uses this to determine which vendors can receive the event. For example, if marketing is false, the event will not be delivered to Meta, TikTok, or other marketing vendors, even though it was collected.

Detection order

When mode is "auto" (the default), Datafly.js checks for CMP cookies in this order:

  1. OptanonConsent (OneTrust)
  2. CookieConsent (Cookiebot)
  3. _df_consent (custom)
  4. Default state (all false unless overridden)

The first match wins. If you have multiple CMPs on the page (not recommended), the first detected CMP takes precedence.