This product is not supported for your selected Datadog site. ().
Overview
This page describes how to instrument your Android or Android TV application with the Datadog Feature Flags SDK. Datadog feature flags provide a unified way to remotely control feature availability in your app, experiment safely, and deliver new experiences with confidence.
The Datadog Feature Flags SDK for Android is built on OpenFeature, an open standard for feature flag management. This guide explains how to install the SDK, configure the Datadog provider, and evaluate flags in your application.
For most applications, the OpenFeature API is the recommended approach. If you need multiple independent evaluation contexts in the same application, see Direct FlagsClient Integration.
Getting started
Here’s a minimal example to get feature flags working in your Android app:
// 1. Add dependencies (see Installation section)
// 2. Initialize Datadog SDK (in Application.onCreate)
valconfiguration=Configuration.Builder(clientToken="<CLIENT_TOKEN>",env="<ENV_NAME>",variant="<APP_VARIANT_NAME>").useSite(DatadogSite.).build()Datadog.initialize(this,configuration,TrackingConsent.GRANTED)// 3. Enable Feature Flags
Flags.enable()// 4. Create and set up the OpenFeature provider
valprovider=FlagsClient.Builder().build().asOpenFeatureProvider()OpenFeatureAPI.setProviderAndWait(provider)// 5. Set evaluation context (who is the user)
OpenFeatureAPI.setEvaluationContext(ImmutableContext(targetingKey="user-123",attributes=mapOf("tier"toValue.String("premium"))))// 6. Evaluate flags anywhere in your app
valclient=OpenFeatureAPI.getClient()valisEnabled=client.getBooleanValue("my-feature",false)
The rest of this guide explains each step in detail.
Installation
Add the Datadog Feature Flags SDK and OpenFeature Provider as Gradle dependencies in your application module’s build.gradle file:
build.gradle
dependencies{implementation"com.datadoghq:dd-sdk-android-flags:<latest-version>"implementation"com.datadoghq:dd-sdk-android-flags-openfeature:<latest-version>"// Recommended: RUM integration drives analysis and enriches RUM session data
implementation"com.datadoghq:dd-sdk-android-rum:<latest-version>"}
Initialize the SDK
Initialize Datadog as early as possible in your app lifecycle—typically in your Application class’s onCreate() method. This helps ensure all feature flag evaluations and telemetry are captured correctly.
Create a FlagsClient and convert it to an OpenFeature provider using the asOpenFeatureProvider() extension. Do this once during app startup:
importcom.datadog.android.flags.FlagsClientimportcom.datadog.android.flags.openfeature.asOpenFeatureProviderimportdev.openfeature.kotlin.sdk.OpenFeatureAPI// Create and configure the provider
valprovider=FlagsClient.Builder().build().asOpenFeatureProvider()// Set it as the OpenFeature provider
OpenFeatureAPI.setProviderAndWait(provider)
The OpenFeature provider wraps a Datadog FlagsClient internally. This is an implementation detail—once set up, you interact exclusively through the standard OpenFeature API.
The OpenFeature Kotlin SDK uses a single global provider and evaluation context. If you need multiple independent evaluation contexts in the same app (for example, for different users in a multi-user app), see Direct FlagsClient Integration.
Set the evaluation context
Define who or what the flag evaluation applies to using an ImmutableContext. The evaluation context includes user or session information used to determine which flag variations should be returned. Set this before evaluating flags to help ensure proper targeting.
All attribute values must use a Value.String() wrapper. The targeting key should be consistent for the same user to help ensure consistent flag evaluation across sessions. For anonymous users, use a persistent UUID stored, for example, in SharedPreferences.
Evaluate flags
After setting up your provider and evaluation context, you can read flag values throughout your app. Flag evaluation is local and instantaneous—the SDK uses locally cached data, so no network requests occur when evaluating flags. This makes evaluations safe to perform on the main thread.
Each flag is identified by a key (a unique string) and can be evaluated with a typed method that returns a value of the expected type. If the flag doesn’t exist or cannot be evaluated, the SDK returns the provided default value.
When you need more than the flag value, you can get detailed evaluation metadata including the evaluated value, variant name, reason, and any error codes:
valdetails=client.getStringDetails(key="paywall.layout",defaultValue="control")print(details.value)// Evaluated value (for example: "A", "B", or "control")
print(details.variant)// Variant name, if applicable
print(details.reason)// Reason for this value (for example: "TARGETING_MATCH" or "DEFAULT")
print(details.errorCode)// Error code, if any
Similar detail methods exist for other types: getBooleanDetails(), getIntegerDetails(), getDoubleDetails(), and getObjectDetails().
Flag details help you debug evaluation behavior and understand why a user received a given value.
Advanced configuration
Global configuration
The Flags.enable() API accepts optional configuration with the options listed below. These settings apply globally to all providers:
valconfig=FlagsConfiguration.Builder()// configure options here
.build()Flags.enable(config)
trackExposures()
When true (default), the SDK automatically records an exposure event when a flag is evaluated. These events contain metadata about which flag was accessed, which variant was served, and under what context. They are sent to Datadog so you can later analyze feature adoption. If you only need local evaluation without telemetry, you can disable it with: trackExposures(false).
rumIntegrationEnabled()
When true (default), flag evaluations are tracked in RUM, which enables correlating them with user sessions. This enables analytics such as “Do users in variant B experience more errors?”. If your app does not use RUM, this flag has no effect and can be safely left at its default value. Use rumIntegrationEnabled(false) to disable RUM integration.
gracefulModeEnabled()
Controls how the SDK handles incorrect use of the API—for example, creating a client before calling Flags.enable(), creating a duplicate client with the same name, or retrieving a client that hasn’t been created yet.
The exact behavior of Graceful Mode depends on your build configuration:
Release builds: The SDK always enforces Graceful Mode: any misuse is only logged internally if Datadog.setVerbosity() is configured.
Debug builds with gracefulModeEnabled = true (default): The SDK always logs warnings to the console.
Debug builds with gracefulModeEnabled = false: The SDK raises IllegalStateException for incorrect API usage, enforcing a fail-fast approach that helps detect configuration mistakes early.
You can adjust gracefulModeEnabled() depending on your development or QA phase.
Per-provider configuration
You can configure individual providers with custom endpoints before creating them:
For most applications, the OpenFeature API described above is the recommended approach. However, you can use the Datadog FlagsClient directly if you have specific requirements that the OpenFeature abstraction doesn’t support.
Use FlagsClient directly only if you:
Require multiple independent evaluation contexts in the same app (for example, different contexts for different users in a multi-user app)
Want to work with native Kotlin types directly (JSONObject instead of Value.Structure)
Need fine-grained control over client lifecycle and configuration per instance
Installation (FlagsClient)
If you only need the direct API, you can omit the OpenFeature dependency:
build.gradle
dependencies{implementation"com.datadoghq:dd-sdk-android-flags:<latest-version>"// Recommended: RUM integration drives analysis and enriches RUM session data
implementation"com.datadoghq:dd-sdk-android-rum:<latest-version>"}
Create and retrieve a client (FlagsClient)
Create a client once, typically during app startup:
FlagsClient.Builder().build()// Creates the default client
Retrieve the same client anywhere in your app:
valflagsClient=FlagsClient.get()// Retrieves the "default" client
You can also create and retrieve multiple clients by providing the name parameter:
This method fetches flag assignments from the server asynchronously in the background. The operation is non-blocking and thread-safe. Flag updates are available for subsequent evaluations after the background operation completes.
valdetails=flagsClient.resolve(flagKey="paywall.layout",defaultValue="control")print(details.value)// Evaluated value (for example: "A", "B", or "control")
print(details.variant)// Variant name, if applicable
print(details.reason)// Description of why this value was chosen
print(details.errorCode)// The error that occurred during evaluation, if any
API comparison
This table highlights key differences between the OpenFeature and FlagsClient APIs to help you choose the integration that fits your requirements.
Feature
OpenFeature
FlagsClient
API Standard
OpenFeature (vendor-neutral)
Datadog-specific
Evaluation Context
Global/static
Per client instance
Structured Flags
Value.Structure
JSONObject
Type Safety
OpenFeature Value types
Kotlin-native types
Vendor Lock-in
Low (vendor-neutral)
Higher (Datadog-specific)
State Management
Flow-based observation
Manual listener registration
Further reading
Additional helpful documentation, links, and articles: