LaunchDarkly + DataGrail Consent
LaunchDarkly is a feature flag and experimentation platform with a critical distinction for consent: server-side feature flags require no consent, while client-side SDK + experimentation require consent. This guide helps you choose the right approach for your compliance needs.
Server-Side vs Client-Side
Understanding the difference between server-side and client-side evaluation is essential for consent compliance:
| Evaluation Type | Browser Storage? | Network Calls? | Consent Required? | Use Case |
|---|---|---|---|---|
| Server-Side | None | None from browser | No | Feature flags evaluated on your backend |
| Client-Side (events off) | localStorage | Streaming connection | Likely (Functional) | Real-time flags with minimal tracking |
| Client-Side (events on) | localStorage | Events + streaming | Yes (Performance) | Flags with analytics/experimentation |
| Experimentation | localStorage | Full event tracking | Yes (Performance) | A/B testing with conversion tracking |
If your primary use case is feature flags (not experimentation), use LaunchDarkly's server-side SDK. Your backend evaluates flags and passes the results to your frontend — no browser storage, no consent requirement.
Recommended Approaches
Gated Client SDK
For client-side experimentation, gate SDK initialization behind DataGrail's callbacks:
<script>
window.dgEvent = window.dgEvent || [];
function initLaunchDarkly(preferences) {
if (window.DG_BANNER_API.categoryEnabled('performance') && !window.ldClient) {
var context = {
kind: 'user',
key: 'user-unique-id',
email: 'user@example.com'
};
var options = {
sendEvents: true,
fetchGoals: true
};
window.ldClient = LDClient.initialize('YOUR_CLIENT_ID', context, options);
window.ldClient.waitForInitialization().then(function() {
var showFeature = window.ldClient.variation('feature-flag-key', false);
});
}
}
window.dgEvent.push({
event: "initial_preference_callback",
params: initLaunchDarkly
});
window.dgEvent.push({
event: "preference_callback",
params: initLaunchDarkly
});
</script>
Server-Side Only
Evaluate flags on your backend and pass flag states to your frontend:
// Backend (Node.js example)
const client = LaunchDarkly.init('YOUR_SERVER_SDK_KEY');
app.get('/api/flags', async (req, res) => {
const context = {
kind: 'user',
key: req.user.id
};
const flags = await client.allFlagsState(context);
res.json(flags.toJSON());
});
// Frontend - no LaunchDarkly SDK, just use flag values from API
fetch('/api/flags')
.then(response => response.json())
.then(flags => {
if (flags['feature-flag-key']) {
// Show feature
}
});
Advantages:
- No browser storage required
- No consent requirement for feature flags
- Reduced client-side JavaScript
- Better security (server controls evaluation rules)
Limited Tracking Mode
If you need real-time flag updates but want to minimize tracking, initialize with events disabled when only Functional consent is granted:
<script>
window.dgEvent = window.dgEvent || [];
function initLaunchDarklyLimited(preferences) {
if (!window.ldClient && window.DG_BANNER_API.categoryEnabled('functional')) {
window.ldClient = LDClient.initialize('YOUR_CLIENT_ID', context, {
sendEvents: false,
fetchGoals: false
});
}
}
window.dgEvent.push({
event: "initial_preference_callback",
params: initLaunchDarklyLimited
});
</script>
This approach uses localStorage for caching but sends no behavioral data to LaunchDarkly.
Storage Patterns
LaunchDarkly exclusively uses localStorage — no cookies are set. Since DataGrail's Cookie Management manages cookie rules, the primary enforcement mechanism for LaunchDarkly is gating SDK initialization behind consent as shown in the patterns above.
LaunchDarkly stores data in localStorage under keys prefixed with LaunchDarkly_. Because no cookies are written, there are no cookie rules to add in the DataGrail dashboard. Instead, control access by only initializing the SDK after consent is granted.
Experimentation Tracking
LaunchDarkly Experimentation tracks these event types:
- feature events — Flag evaluation context
- click events — Element interactions
- page view events — URL visits
- custom events — Conversion goals you define
- summary events — Aggregated flag evaluations
All experimentation tracking requires Performance consent. Use the sendEvents and fetchGoals options to control tracking:
<script>
window.dgEvent = window.dgEvent || [];
function initLaunchDarklyTiered(preferences) {
if (window.ldClient) return;
var context = { kind: 'user', key: 'anonymous-user' };
if (window.DG_BANNER_API.categoryEnabled('performance')) {
window.ldClient = LDClient.initialize('YOUR_CLIENT_ID', context, {
sendEvents: true,
fetchGoals: true
});
} else if (window.DG_BANNER_API.categoryEnabled('functional')) {
window.ldClient = LDClient.initialize('YOUR_CLIENT_ID', context, {
sendEvents: false,
fetchGoals: false
});
}
}
window.dgEvent.push({
event: "initial_preference_callback",
params: initLaunchDarklyTiered
});
window.dgEvent.push({
event: "preference_callback",
params: initLaunchDarklyTiered
});
</script>
Enforcement Strategy
Since LaunchDarkly uses localStorage rather than cookies, the best enforcement strategy is to gate SDK initialization behind consent callbacks rather than trying to block storage. The patterns in the Recommended Approaches section show how to only initialize the client SDK after the appropriate consent category is granted.
Privacy Controls
LaunchDarkly provides these privacy controls you can combine with DataGrail consent:
| Control | Purpose | Use Case |
|---|---|---|
sendEvents: false | Disables all analytics | Flags without measurement |
fetchGoals: false | Disables experimentation metrics | Flags without experiments |
privateAttributes | Prevents specific fields from being stored | Mask PII in context |
eventUrlTransformer | Redacts URLs in events | Remove sensitive query params |
| EU endpoints | Uses .eu.launchdarkly.com | Data residency requirements |
Consent Category Guidance
Here's how to classify LaunchDarkly based on your usage:
| Your Usage | Suggested Category | DataGrail Action |
|---|---|---|
| Server-side flags only | Strictly Necessary | No consent required |
| Client SDK for flags (no events) | Functional | Gate initialization behind functional consent |
| Client SDK with experimentation | Performance | Gate initialization behind performance consent |
| Session Replay enabled | Performance | Requires explicit performance consent |
Troubleshooting
LaunchDarkly SDK initializes before consent is collected
Ensure:
- You're not initializing the SDK in a global script
- SDK initialization is inside your
initial_preference_callbackorpreference_callbackhandler - You're checking
window.DG_BANNER_API.categoryEnabled('performance')before initializing - The DataGrail banner script loads before your callback registration
Feature flags don't update in real-time
This usually means:
- You're using server-side evaluation without a streaming connection
- Client SDK isn't initialized (consent not granted)
- Streaming connection is blocked by a firewall/proxy
- You need to reload flag state from your backend API
localStorage blocked errors in browser console
This is expected behavior when:
- DataGrail is blocking localStorage until consent
- User has denied consent but your code is trying to initialize SDK
- Solution: Only initialize SDK after confirming consent is granted
Want flags immediately but experimentation gated
Use the two-tier approach:
- Server-side evaluation provides flag values on page load (no consent needed)
- Client SDK initializes after consent for experimentation only
- Flags work immediately; tracking starts post-consent
LaunchDarkly v4 Breaking Changes
If you're using LaunchDarkly JS SDK v4.x or later:
- localStorage caching is ON by default (was opt-in in v3)
- DNT (Do Not Track) support was REMOVED — you must implement consent gating manually
- Device ID (
ld_devicecontext key) is automatically generated and persisted
These changes make v4 more reliant on consent management than v3. Ensure you're properly gating SDK initialization.
Related Resources
- LaunchDarkly Privacy Documentation
- DataGrail Consent Banner Documentation
- For questions, contact support@datagrail.io
Disclaimer: The information contained in this message does not constitute as legal advice. We would advise seeking professional counsel before acting on or interpreting any material.