This product is not supported for your selected Datadog site. ().
Overview
This guide explains how to use Datadog Feature Flags to run Experiments with a headless content management system (CMS) such as Contentful, Builder.io, or Strapi. Instead of hardcoding content into your flag variants, you author all content variations directly in your CMS. Use a string or JSON flag to map each variant to a content or model ID, which your frontend resolves at render time. This keeps content management in editors’ hands while giving engineers full observability through Datadog.
The core pattern:
Content authors create multiple content entries (variants) in the CMS.
Engineers create a Datadog feature flag whose variants are strings (such as a Contentful Entry ID) or JSON objects (for example, { "entryId": "abc123", "label": "spring-promotion" }).
On page load, the flag is evaluated for the current user and the returned value is used to fetch the matching CMS content.
A Datadog account with Feature Flags and Product Analytics enabled
The Datadog RUM Browser SDK installed in your frontend application
A headless CMS account such as: Contentful, Builder.io, or Strapi
Node.js / React (examples below use the React SDK; vanilla JavaScript and other frameworks are also supported)
Step 1: Author content variants in your CMS
Before creating a flag, set up your content variants in your CMS. Each variant should be a separate content entry—do not try to pack multiple variants into a single entry. Datadog flags also allow for multiple variations on a flag, enabling A/B/n and multivariate tests. The following section provides vendor-specific examples for Contentful, Builder.io, and Strapi; these patterns can be extended to any headless or API-based CMS.
Create two or more entries of the same content type (for example, HeroBanner). Note the Entry ID for each, which is visible in the entry URL or the Contentful web app sidebar.
Entry A (Control): Entry ID = "1a2b3c4d5e6f" → "Shop the Spring Collection"
Entry B (Variant): Entry ID = "7g8h9i0j1k2l" → "Up to 40% Off — Limited Time"
Create two pages or sections in Builder.io targeting the same URL path or component slot. Note the model ID or page ID for each entry, accessible from the Builder.io Content tab or API explorer.
Entry A (Control): Page ID = "builder-page-control-001"
Entry B (Variant): Page ID = "builder-page-variant-001"
Create two entries of the same collection type (for example, homepage-hero). Note the document ID (integer or UID) from the Strapi admin panel.
Entry A (Control): Document ID = 42
Entry B (Variant): Document ID = 43
Step 2: Install the Datadog Feature Flags SDK
The following examples use the React SDK for illustration purposes. For other frameworks and languages, see Client-Side Feature Flags.
Initialize the Datadog provider early in your application’s life cycle (for example, in index.tsx or _app.tsx):
providers/datadogFeatureFlags.ts
import{DatadogProvider}from'@datadog/openfeature-browser';import{OpenFeature}from'@openfeature/web-sdk';constprovider=newDatadogProvider({applicationId:'<YOUR_APPLICATION_ID>',clientToken:'<YOUR_CLIENT_TOKEN>',site:'datadoghq.com',// or datadoghq.eu, us3.datadoghq.com, etc.
env:'<YOUR_ENVIRONMENT>',// For example: 'production', 'staging'
});constevaluationContext={targetingKey:'user-123',// Used for randomization when bucketing
user_id:'123',email:'user@example.com',tier:'premium',};// Set evaluation context with user attributes used for targeting rules
OpenFeature.setProvider(provider,evaluationContext);
Wrap your application with the OpenFeatureProvider:
Set up targeting rules (for example, roll out to 50% of users, or target by tier: premium).
Save and activate the flag in your target environment.
Step 4: Evaluate the flag and fetch CMS content
Using a string flag (simple entry ID)
components/HeroBanner.tsx
import{useStringFlagDetails}from'@openfeature/react-sdk';import{useEffect,useState}from'react';import{datadogRum}from'@datadog/browser-rum';constDEFAULT_ENTRY_ID='1a2b3c4d5e6f';// Fallback / control entry ID
exportfunctionHeroBanner() {constflagDetails=useStringFlagDetails('cms_homepage_hero_variant',DEFAULT_ENTRY_ID);constentryId=flagDetails.value;const[content,setContent]=useState(null);useEffect(()=>{if(!entryId)return;// Fetch the content entry from Contentful using the resolved entry ID
fetchContentfulEntry(entryId).then((data)=>{setContent(data);});},[entryId]);if(!content)return<div>Loading...</div>;return(<sectionclassName="hero-banner"><h1>{content.headline}</h1><p>{content.subheadline}</p><ahref={content.ctaUrl}onClick={()=>trackCtaClick(entryId,flagDetails.variant)}>{content.ctaText}</a></section>);}// RUM custom action: track CTA clicks, variation context is automatically enriched in RUM events
functiontrackCtaClick(entryId: string,variant: string|undefined){datadogRum.addAction('hero_cta_click',{cms_entry_id: entryId,component:'HeroBanner',});}
To measure experiment results in Product Analytics, trigger RUM custom actions at key moments in the user journey. These become the metrics used in your experiment.
lib/tracking.ts
import{datadogRum}from'@datadog/browser-rum';// Called on component mount / content impression
exportfunctiontrackContentImpression(entryId: string,variantLabel: string){datadogRum.addAction('cms_content_impression',{cms_entry_id: entryId,variant_label: variantLabel,});}// Called when the user clicks the primary CTA
exportfunctiontrackCtaClick(entryId: string,variantLabel: string){datadogRum.addAction('cms_cta_click',{cms_entry_id: entryId,variant_label: variantLabel,});}// Called on a successful conversion event (for example, form submit, checkout, signup)
exportfunctiontrackConversion(entryId: string,variantLabel: string,conversionType: string){datadogRum.addAction('form_conversion',{cms_entry_id: entryId,variant_label: variantLabel,conversion_type: conversionType,// For example: 'newsletter_signup', 'add_to_cart'
});}
Step 6: Create experiment metrics in Product Analytics
After your RUM actions are flowing, define the metrics your experiment measures.
In Datadog, navigate to Digital Experience > Product Analytics > Metrics.
Click + Create Metric.
Select the relevant RUM action as the event (for example, cms_cta_click).
Choose an aggregation method:
Unique subjects: Users who clicked at least once; best for conversion rate
Total events: Total clicks; best for engagement volume
Optionally add filters (for example, @context.component: HeroBanner).
Name the metric (for example, hero_cta_click_rate).
Repeat for each metric in your experiment (for example, hero_conversion_rate, page_engagement_time).
Metrics are normalized by the number of enrolled subjects automatically. You can also set an outlier truncation threshold (for example, 99th percentile) and configure whether an increase or decrease is the desired outcome.
Step 7: Launch the experiment
Navigate to Digital Experience > Product Analytics > Experiments.
Click + Create Experiment.
Enter a name and hypothesis, for example:
“Showing a discount-led hero banner (Treatment) increases CTA click-through rate compared to the seasonal collection banner (Control).”
Click Set up experiment on feature flag and select cms_homepage_hero_variant.
Choose rollout strategy: all traffic or a gradual percentage rollout.
Assign your primary metric (hero_cta_click_rate) and optional guardrail metrics (for example, page_load_error_rate).
Launch the experiment.
Step 8: Monitor and read results
Use the following tools in Datadog to monitor and analyze your experiment results:
Real-time flag health: From the feature flag’s details page, monitor:
Exposure counts per variant
Error rates per variant
Page load time per variant
Experiment results: Navigate to your experiment’s details page to see:
Statistical significance of results
Per-variant metric breakdowns
Guardrail metric status
RUM Explorer analysis: Use the RUM Explorer to filter by flag variant: