Overview

Feature flag data gives you greater visibility into your user experience and performance monitoring by allowing you to determine which users are being shown a specific feature and if any change you introduce is impacting your user experience or negatively affecting performance.

By enriching your RUM data with feature flag data, you can be confident that your feature successfully launches without unintentionally causing a bug or performance regression. With this additional layer of insight, you can correlate feature releases with performance, pinpoint issues to specific releases, and troubleshoot faster.

Setup

Feature flag tracking is available in the RUM Browser SDK. To start, set up RUM browser monitoring. You need the Browser RUM SDK version >= 4.25.0.

To start collecting feature flag data, initialize the RUM SDK and configure the enableExperimentalFeatures initialization parameter with ["feature_flags"].

npm
  import { datadogRum } from '@datadog/browser-rum';

  // Initialize Datadog Browser SDK
  datadogRum.init({
    ...
    enableExperimentalFeatures: ["feature_flags"],
    ...
});
CDN async
window.DD_RUM.onReady(function() {
    window.DD_RUM.init({
      ...
      enableExperimentalFeatures: ["feature_flags"],
      ...
    })
})
CDN sync
window.DD_RUM &&
    window.DD_RUM.init({
      ...
      enableExperimentalFeatures: ["feature_flags"],
      ...
    })

Feature flag tracking is available in the RUM iOS SDK. To start, set up RUM iOS monitoring. You need the iOS RUM SDK version >= 1.16.0.

Feature flag tracking is available in the RUM Android SDK. To start, set up RUM Android monitoring. You need the Android RUM SDK version >= 1.18.0.

Feature flag tracking is available for your Flutter applications. To start, set up RUM Flutter monitoring. You need the Flutter Plugin version >= 1.3.2.

Feature flag tracking is available for your React Native applications. To start, set up RUM React Native monitoring. You need the React Native RUM SDK version >= 1.7.0.

Integrations

You can start collecting feature flag data with custom feature flag management solutions, or by using one of Datadog’s integration partners.

Datadog supports integrations with:

amplitude
custom
devcycle
eppo
flagsmith
launchdarkly
split
statsig


Amplitude integration

Initialize Amplitude’s SDK and create an exposure listener reporting feature flag evaluations to Datadog using the following snippet of code:

For more information about initializing Amplitude’s SDK, see Amplitude’s JavaScript SDK documentation.

  const experiment = Experiment.initialize("CLIENT_DEPLOYMENT_KEY", {
    exposureTrackingProvider: {
      track(exposure: Exposure)  {
        // Send the feature flag when Amplitude reports the exposure
        datadogRum.addFeatureFlagEvaluation(exposure.flag_key, exposure.variant);
      }
    }
  })

Initialize Amplitude’s SDK and create an inspector reporting feature flag evaluations to Datadog using the snippet of code below.

For more information about initializing Amplitude’s SDK, see Amplitude’s iOS SDK documentation.

  class DatadogExposureTrackingProvider : ExposureTrackingProvider {
    func track(exposure: Exposure) {
      // Send the feature flag when Amplitude reports the exposure
      if let variant = exposure.variant {
        RUMMonitor.shared().addFeatureFlagEvaluation(name: exposure.flagKey, value: variant)
      }
    }
  }

  // In initialization:
  ExperimentConfig config = ExperimentConfigBuilder()
    .exposureTrackingProvider(DatadogExposureTrackingProvider(analytics))
    .build()

Initialize Amplitude’s SDK and create an inspector reporting feature flag evaluations to Datadog using the snippet of code below.

For more information about initializing Amplitude’s SDK, see Amplitude’s Android SDK documentation.

  internal class DatadogExposureTrackingProvider : ExposureTrackingProvider {
    override fun track(exposure: Exposure) {
        // Send the feature flag when Amplitude reports the exposure
        GlobalRumMonitor.get().addFeatureFlagEvaluation(
            exposure.flagKey,
            exposure.variant.orEmpty()
        )
    }
  }

  // In initialization:
  val config = ExperimentConfig.Builder()
      .exposureTrackingProvider(DatadogExposureTrackingProvider())
      .build()

Amplitude does not support this integration. Create a ticket with Amplitude to request this feature.

Custom feature flag management

Each time a feature flag is evaluated, add the following function to send the feature flag information to RUM:

datadogRum.addFeatureFlagEvaluation(key, value);

Each time a feature flag is evaluated, add the following function to send the feature flag information to RUM:

RUMMonitor.shared().addFeatureFlagEvaluation(key, value);

Each time a feature flag is evaluated, add the following function to send the feature flag information to RUM:

GlobalRumMonitor.get().addFeatureFlagEvaluation(key, value);

Each time a feature flag is evaluated, add the following function to send the feature flag information to RUM:

DatadogSdk.instance.rum?.addFeatureFlagEvaluation(key, value);

Each time a feature flag is evaluated, add the following function to send the feature flag information to RUM:

DdRum.addFeatureFlagEvaluation(key, value);

DevCycle integration

Initialize DevCycle’s SDK and subscribe to the variableEvaluated event, choosing to subscribe to all variable evaluations variableEvaluated:* or particular variable evaluations variableEvaluated:my-variable-key.

For more information about initializing DevCycle’s SDK, see DevCycle’s JavaScript SDK documentation and for more information about DevCycle’s event system, see DevCycle’s SDK Event Documentation.

const user = { user_id: "<USER_ID>" };
const dvcOptions = { ... };
const dvcClient = initialize("<DVC_CLIENT_SDK_KEY>", user, dvcOptions);
...
dvcClient.subscribe(
    "variableEvaluated:*",
    (key, variable) => {
        // track all variable evaluations
        datadogRum.addFeatureFlagEvaluation(key, variable.value);
    }
)
...
dvcClient.subscribe(
    "variableEvaluated:my-variable-key",
    (key, variable) => {
        // track a particular variable evaluation
        datadogRum.addFeatureFlagEvaluation(key, variable.value);
    }
)

DevCycle does not support this integration. Create a ticket with DevCycle to request this feature.

DevCycle does not support this integration. Create a ticket with DevCycle to request this feature.

DevCycle does not support this integration. Create a ticket with DevCycle to request this feature.

DevCycle does not support this integration. Create a ticket with DevCycle to request this feature.

Eppo integration

Initialize Eppo’s SDK and create an assignment logger that additionally reports feature flag evaluations to Datadog using the snippet of code shown below.

For more information about initializing Eppo’s SDK, see Eppo’s JavaScript SDK documentation.

const assignmentLogger: IAssignmentLogger = {
  logAssignment(assignment) {
    datadogRum.addFeatureFlagEvaluation(assignment.featureFlag, assignment.variation);
  },
};

await eppoInit({
  apiKey: "<API_KEY>",
  assignmentLogger,
});

Initialize Eppo’s SDK and create an assignment logger that additionally reports feature flag evaluations to Datadog using the snippet of code shown below.

For more information about initializing Eppo’s SDK, see Eppo’s iOS SDK documentation.

func IAssignmentLogger(assignment: Assignment) {
  RUMMonitor.shared().addFeatureFlagEvaluation(featureFlag: assignment.featureFlag, variation: assignment.variation)
}

let eppoClient = EppoClient(apiKey: "mock-api-key", assignmentLogger: IAssignmentLogger)

Initialize Eppo’s SDK and create an assignment logger that additionally reports feature flag evaluations to Datadog using the snippet of code shown below.

For more information about initializing Eppo’s SDK, see Eppo’s Android SDK documentation.

AssignmentLogger logger = new AssignmentLogger() {
    @Override
    public void logAssignment(Assignment assignment) {
      GlobalRumMonitor.get().addFeatureFlagEvaluation(assignment.getFeatureFlag(), assignment.getVariation());
    }
};

EppoClient eppoClient = new EppoClient.Builder()
    .apiKey("YOUR_API_KEY")
    .assignmentLogger(logger)
    .application(application)
    .buildAndInit();

Eppo does not support this integration. Contact Eppo to request this feature.

Initialize Eppo’s SDK and create an assignment logger that additionally reports feature flag evaluations to Datadog using the snippet of code shown below.

For more information about initializing Eppo’s SDK, see Eppo’s React native SDK documentation.

const assignmentLogger: IAssignmentLogger = {
  logAssignment(assignment) {
    DdRum.addFeatureFlagEvaluation(assignment.featureFlag, assignment.variation);
  },
};

await eppoInit({
  apiKey: "<API_KEY>",
  assignmentLogger,
});

Flagsmith Integration

Initialize Flagsmith’s SDK with the datadogRum option, which reports feature flag evaluations to Datadog using the snippet of code shown below.

Optionally, you can configure the client so that Flagsmith traits are sent to Datadog via datadogRum.setUser(). For more information about initializing Flagsmith’s SDK, check out Flagsmith’s JavaScript SDK documentation.

 // Initialize the Flagsmith SDK
 flagsmith.init({
     datadogRum: {
         client: datadogRum,
         trackTraits: true,
     },
     ...
 })

Flagsmith does not support this integration. Create a ticket with Flagsmith to request this feature.

Flagsmith does not support this integration. Create a ticket with Flagsmith to request this feature.

Flagsmith does not support this integration. Create a ticket with Flagsmith to request this feature.

Flagsmith does not currently support this integration. Create a ticket with Flagsmith to request this feature.

LaunchDarkly integration

Initialize LaunchDarkly’s SDK and create an inspector reporting feature flags evaluations to Datadog using the snippet of code shown below.

For more information about initializing LaunchDarkly’s SDK, see LaunchDarkly’s JavaScript SDK documentation.

const client = LDClient.initialize("<CLIENT_SIDE_ID>", "<CONTEXT>", {
  inspectors: [
    {
      type: "flag-used",
      name: "dd-inspector",
      method: (key: string, detail: LDClient.LDEvaluationDetail) => {
        datadogRum.addFeatureFlagEvaluation(key, detail.value);
      },
    },
  ],
});

LaunchDarkly does not support this integration. Create a ticket with LaunchDarkly to request this feature.

LaunchDarkly does not support this integration. Create a ticket with LaunchDarkly to request this feature.

LaunchDarkly does not support this integration. Create a ticket with LaunchDarkly to request this feature.

LaunchDarkly does not currently support this integration. Create a ticket with LaunchDarkly to request this feature.

Split Integration

Initialize Split’s SDK and and create an impression listener reporting feature flag evaluations to Datadog using the following snippet of code:

For more information about initializing Split’s SDK, see Split’s JavaScript SDK documentation.

const factory = SplitFactory({
    core: {
      authorizationKey: "<APP_KEY>",
      key: "<USER_ID>",
    },
    impressionListener: {
      logImpression(impressionData) {
          datadogRum
              .addFeatureFlagEvaluation(
                  impressionData.impression.feature,
                  impressionData.impression.treatment
              );
    },
  },
});

const client = factory.client();

Initialize Split’s SDK and create an inspector reporting feature flag evaluations to Datadog using the snippet of code below.

For more information about initializing Split’s SDK, see Split’s iOS SDK documentation.

  let config = SplitClientConfig()
  // Send the feature flag when Split reports the impression
  config.impressionListener = { impression in
      if let feature = impression.feature,
          let treatment = impression.treatment {
          RUMMonitor.shared().addFeatureFlagEvaluation(name: feature, value: treatment)
      }
  }

Initialize Split’s SDK and create an inspector reporting feature flag evaluations to Datadog using the snippet of code below.

For more information about initializing Split’s SDK, see Split’s Android SDK documentation.

  internal class DatadogSplitImpressionListener : ImpressionListener {
    override fun log(impression: Impression) {
        // Send the feature flag when Split reports the impression
        GlobalRumMonitor.get().addFeatureFlagEvaluation(
            impression.split(),
            impression.treatment()
        )
    }
    override fun close() {
    }
  }

  // In initialization:
  val apikey = BuildConfig.SPLIT_API_KEY
  val config = SplitClientConfig.builder()
      .impressionListener(DatadogSplitImpressionListener())
      .build()

Initialize Split’s SDK and create an inspector reporting feature flag evaluations to Datadog using the snippet of code below.

For more information about initializing Split’s SDK, see Split’s Flutter plugin documentation.

  StreamSubscription<Impression> impressionsStream = _split.impressionsStream().listen((impression) {
    // Send the feature flag when Split reports the impression
    final split = impression.split;
    final treatment = impression.treatment;
    if (split != null && treatment != null) {
      DatadogSdk.instance.rum?.addFeatureFlagEvaluation(split, treatment);
    }
  });

Initialize Split’s SDK and and create an impression listener reporting feature flag evaluations to Datadog using the following snippet of code:

For more information about initializing Split’s SDK, see Split’s React Native SDK documentation.

const factory = SplitFactory({
    core: {
      authorizationKey: "<APP_KEY>",
      key: "<USER_ID>",
    },
    impressionListener: {
      logImpression(impressionData) {
          DdRum
              .addFeatureFlagEvaluation(
                  impressionData.impression.feature,
                  impressionData.impression.treatment
              );
    },
  },
});

const client = factory.client();

Statsig Integration

Initialize Statsig’s SDK with statsig.initialize.

  1. Update your Browser RUM SDK version 4.25.0 or above.

  2. Initialize the RUM SDK and configure the enableExperimentalFeatures initialization parameter with ["feature_flags"].

  3. Initialize Statsig’s SDK (>= v4.34.0) and implement the gateEvaluationCallback option as shown below:

     await statsig.initialize('client-<STATSIG CLIENT KEY>',
     {userID: '<USER ID>'},
     {
         gateEvaluationCallback: (key, value) => {
             datadogRum.addFeatureFlagEvaluation(key, value);
         }
     }
     );
    

Statsig does not support this integration. Contact support@statsig.com to request this feature.

Statsig does not support this integration. Contact support@statsig.com to request this feature.

Statsig does not support this integration. Contact support@statsig.com to request this feature.

Statsig does not currently support this integration. Contact support@statsig.com to request this feature.

Analyze your Feature Flag performance in RUM

Feature flags appear in the context of your RUM Sessions, Views, and Errors as a list.

Feature Flag list of attributes in RUM Explorer

Search feature flags using the RUM Explorer

Search through all the data collected by RUM in the RUM Explorer to surface trends on feature flags, analyze patterns with greater context, or export them into dashboards and monitors. You can search your Sessions, Views, or Errors in the RUM Explorer, with the @feature_flags.{flag_name} attribute.

Sessions

Filtering your Sessions with the @feature_flags.{flag_name} attribute, you can find all sessions in the given time frame where your feature flag was evaluated.

Search Sessions for Feature Flags in the RUM Explorer

Views

Filtering your Views with the @feature_flags.{flag_name} attribute, you can find the specific views in the given time frame where your feature flag was evaluated.

Search Views for Feature Flags in the RUM Explorer

Errors

Filtering your Errors with the @feature_flags.{flag_name} attribute, you can find all the errors in the given time frame that occurred on the View where your feature flag was evaluated

Search Errors for Feature Flags in the RUM Explorer

Troubleshooting

Why doesn’t my feature flag data reflect what I expect to see?

Feature flags show up in the context of events where they are evaluated, meaning they should show up on the views that the feature flag code logic is run on.

Depending on how you’ve structured your code and set up your feature flags, you may see unexpected feature flags appear in the context of some events.

For example, to see what Views your feature flag is being evaluated on, you can use the RUM Explorer to make a similar query:

Search Views for Feature Flags in the RUM Explorer

Here are a few examples of reasons why your feature flag is being evaluated on unrelated Views that can help with your investigations:

  • A common react component that appears on multiple pages which evaluates feature flags whenever they run.
  • A routing issue where components with a feature flag evaluation are rendered before/after URL changes.

When performing your investigations, you can also scope your data for View Name’s that are relevant to your feature flag.

Feature flag naming

The following special characters are not supported for Feature Flag Tracking: ., :, +, -, =, &&, ||, >, <, !, (, ), {, }, [, ], ^, ", , , ~, *, ?, \. Datadog recommends avoiding these characters when possible in your feature flag names. If you are required to use one of these characters, replace the character before sending the data to Datadog. For example:

datadogRum.addFeatureFlagEvaluation(key.replace(':', '_'), value);

Further Reading