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).
How consent works in Datafly
Consent is enforced at two levels:
- 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.
- 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 │
└──────────────┘ └──────────────────┘ └─────────────────┘Consent categories
Datafly uses three consent categories that map to standard CMP groupings:
| Category | Description | Example vendors |
|---|---|---|
analytics | Performance and analytics cookies/tracking | Google Analytics 4 |
marketing | Advertising and targeting | Meta Pixel, TikTok, Pinterest, Snapchat |
functional | Functional and preference cookies | A/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 group | Datafly 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 field | Datafly category |
|---|---|
necessary | Always allowed |
statistics | analytics |
preferences | functional |
marketing | marketing |
Custom / Datafly consent cookie
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=1Values of 1 or true indicate consent granted. Values of 0 or false indicate consent denied.
Configuration
Default consent state
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:
| Mode | CMP | Cookie read |
|---|---|---|
"onetrust" | OneTrust | OptanonConsent |
"cookiebot" | Cookiebot | CookieConsent |
"custom" | Your own CMP | _df_consent |
"auto" (default) | Auto-detect | Checks 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.
Custom consent integration
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';
});Reading consent state
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.
Client-side tag injection and 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 === trueConsent is re-checked at the time of injection. If a user revokes consent, subsequently scheduled tags will not be injected.
Consent in the event payload
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:
OptanonConsent(OneTrust)CookieConsent(Cookiebot)_df_consent(custom)- Default state (all
falseunless overridden)
The first match wins. If you have multiple CMPs on the page (not recommended), the first detected CMP takes precedence.