From 1f5a51828da3d9fa983b5460c1a2d4c38344972e Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 17 Mar 2026 10:18:21 -0600 Subject: [PATCH 01/18] Add Unity Feature Flags documentation Add comprehensive Unity Feature Flags documentation with two implementations: 1. unity.md - Direct FlagsClient API (current implementation) - Uses DdFlags.CreateClient() and direct FlagsClient methods - Synchronous flag evaluation (GetBooleanValue, GetStringValue, etc.) - Simpler API without async/await 2. unity-openfeature.md - OpenFeature integration (future/alternative) - Uses OpenFeature Api.Instance.GetClient() - Async flag evaluation methods - Standards-based approach Both pages: - Include cross-links to each other for easy navigation - Follow the structure of Android/iOS feature flags docs - Include installation, setup, evaluation, and advanced config sections - Add Unity card to feature flags client navigation The documentation is ready for preview and user feedback. --- .../feature_flags/client/unity-openfeature.md | 278 ++++++++++++++++++ content/en/feature_flags/client/unity.md | 266 +++++++++++++++++ .../feature_flags/feature_flags_client.html | 7 + 3 files changed, 551 insertions(+) create mode 100644 content/en/feature_flags/client/unity-openfeature.md create mode 100644 content/en/feature_flags/client/unity.md diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md new file mode 100644 index 00000000000..408944dfc89 --- /dev/null +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -0,0 +1,278 @@ +--- +title: Unity Feature Flags (OpenFeature) +description: Set up Datadog Feature Flags for Unity applications using OpenFeature. +aliases: + - /feature_flags/setup/unity-openfeature/ +further_reading: +- link: "/feature_flags/client/" + tag: "Documentation" + text: "Client-Side Feature Flags" +- link: "/real_user_monitoring/application_monitoring/unity/" + tag: "Documentation" + text: "Unity Monitoring" +- link: "https://github.com/DataDog/dd-sdk-unity" + tag: "Source Code" + text: "dd-sdk-unity source code" +--- + +{{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} +Feature Flags are in Preview. Complete the form to request access. +{{< /callout >}} + +
This page documents the OpenFeature integration for Unity Feature Flags. For the direct FlagsClient API (without OpenFeature), see Unity Feature Flags.
+ +## Overview + +This page describes how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. Datadog feature flags provide a unified way to remotely control feature availability in your app, experiment safely, and deliver new experiences with confidence. + +This guide explains how to install and enable the SDK, create and use a flags client with OpenFeature, and configure advanced options. + +## Installation + +Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. + +1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. + +2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. + +3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. + +4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: + + ```groovy + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } + ``` + +## Initialize the SDK + +Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. + +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. + +## Enable flags + +After initializing Datadog, enable flags in your application code: + +{{< code-block lang="csharp" >}} +using Datadog.Unity; +using Datadog.Unity.Flags; + +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, +}); +{{< /code-block >}} + +You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). + +## Create and retrieve a client + +Create a client once, typically during app startup: + +{{< code-block lang="csharp" >}} +DdFlags.CreateClient(); // Creates the default client +{{< /code-block >}} + +Retrieve the same client anywhere in your app using the OpenFeature API: + +{{< code-block lang="csharp" >}} +using OpenFeature; + +var client = Api.Instance.GetClient(); +{{< /code-block >}} + +You can also create and retrieve multiple clients by providing the `name` parameter: + +{{< code-block lang="csharp" >}} +DdFlags.CreateClient("checkout"); +var client = Api.Instance.GetClient("checkout"); +{{< /code-block >}} + +
If a client with the given name already exists, the existing instance is reused.
+ +## Set the evaluation context + +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. + +{{< code-block lang="csharp" >}} +DdFlags.SetEvaluationContext( + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" } + } + ), + onComplete: success => + { + if (success) + { + Debug.Log("Flags loaded successfully!"); + } + } +); +{{< /code-block >}} + +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 once the background operation completes. + +## Evaluate flags + +After creating the client and setting its evaluation context, you can start reading 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. + +The Unity SDK uses the [OpenFeature][6] standard API for flag evaluation. + +### Boolean flags + +Use `GetBooleanValueAsync(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: + +{{< code-block lang="csharp" >}} +var client = Api.Instance.GetClient(); + +var isNewCheckoutEnabled = await client.GetBooleanValueAsync( + flagKey: "checkout.new", + defaultValue: false +); + +if (isNewCheckoutEnabled) +{ + ShowNewCheckoutFlow(); +} +else +{ + ShowLegacyCheckout(); +} +{{< /code-block >}} + +### String flags + +Use `GetStringValueAsync(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: + +{{< code-block lang="csharp" >}} +var theme = await client.GetStringValueAsync( + flagKey: "ui.theme", + defaultValue: "light" +); + +switch (theme) +{ + case "light": + SetLightTheme(); + break; + case "dark": + SetDarkTheme(); + break; + default: + SetLightTheme(); + break; +} +{{< /code-block >}} + +### Integer and double flags + +For numeric flags, use `GetIntegerValueAsync(key, defaultValue)` or `GetDoubleValueAsync(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: + +{{< code-block lang="csharp" >}} +var maxItems = await client.GetIntegerValueAsync( + flagKey: "cart.items.max", + defaultValue: 20 +); + +var priceMultiplier = await client.GetDoubleValueAsync( + flagKey: "pricing.multiplier", + defaultValue: 1.0 +); +{{< /code-block >}} + +### Object flags + +For structured or JSON-like data, use `GetObjectValueAsync(key, defaultValue)`. This method returns an OpenFeature `Value` object, which can represent primitives, arrays, or dictionaries. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: + +{{< code-block lang="csharp" >}} +var config = await client.GetObjectValueAsync( + flagKey: "ui.config", + defaultValue: new Value(new Structure(new Dictionary + { + { "color", new Value("#00A3FF") }, + { "fontSize", new Value(14) } + })) +); + +var color = config.AsStructure["color"].AsString; +var fontSize = config.AsStructure["fontSize"].AsInteger; +{{< /code-block >}} + +### Flag evaluation details + +When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: + +* `GetBooleanDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetStringDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetIntegerDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetDoubleDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetObjectDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` + +For example: + +{{< code-block lang="csharp" >}} +var details = await client.GetStringDetailsAsync( + flagKey: "paywall.layout", + defaultValue: "control" +); + +Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") +Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable +Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") +Debug.Log($"ErrorType: {details.ErrorType}"); // The error that occurred during evaluation, if any +{{< /code-block >}} + +Flag details may help you debug evaluation behavior and understand why a user received a given value. + +## Advanced configuration + +The `DdFlags.Enable()` API accepts optional configuration with options listed below. + +{{< code-block lang="csharp" >}} +var config = new FlagsConfiguration +{ + // configure options here +}; + +DdFlags.Enable(config); +{{< /code-block >}} + +`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. Set to `false` to disable exposure tracking. + +`TrackEvaluations` +: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. + +`EvaluationFlushIntervalSeconds` +: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. + +`CustomFlagsEndpoint` +: Configures a custom server URL for retrieving flag assignments. + +`CustomExposureEndpoint` +: Configures a custom server URL for sending flags exposure data. + +`CustomEvaluationEndpoint` +: Configures a custom server URL for sending flags evaluation telemetry. + +## Further reading + +{{< partial name="whats-next/whats-next.html" >}} + +[1]: https://github.com/googlesamples/unity-jar-resolver +[2]: https://openupm.com/packages/com.google.external-dependency-manager/ +[3]: https://github.com/DataDog/unity-package +[4]: https://docs.unity3d.com/Manual/gradle-templates.html +[5]: /real_user_monitoring/application_monitoring/unity/setup +[6]: https://openfeature.dev/ diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md new file mode 100644 index 00000000000..83780ba0f49 --- /dev/null +++ b/content/en/feature_flags/client/unity.md @@ -0,0 +1,266 @@ +--- +title: Unity Feature Flags +description: Set up Datadog Feature Flags for Unity applications. +aliases: + - /feature_flags/setup/unity/ +further_reading: +- link: "/feature_flags/client/" + tag: "Documentation" + text: "Client-Side Feature Flags" +- link: "/real_user_monitoring/application_monitoring/unity/" + tag: "Documentation" + text: "Unity Monitoring" +- link: "https://github.com/DataDog/dd-sdk-unity" + tag: "Source Code" + text: "dd-sdk-unity source code" +--- + +{{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} +Feature Flags are in Preview. Complete the form to request access. +{{< /callout >}} + +
This page documents the direct FlagsClient API for Unity Feature Flags. If you're looking for OpenFeature integration, see Unity Feature Flags (OpenFeature).
+ +## Overview + +This page describes how to instrument your Unity 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. + +This guide explains how to install and enable the SDK, create and use a `FlagsClient`, and configure advanced options. + +## Installation + +Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. + +1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. + +2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. + +3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. + +4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: + + ```groovy + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } + ``` + +## Initialize the SDK + +Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. + +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. + +## Enable flags + +After initializing Datadog, enable flags in your application code: + +{{< code-block lang="csharp" >}} +using Datadog.Unity.Flags; + +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, +}); +{{< /code-block >}} + +You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). + +## Create and retrieve a client + +Create a client once, typically during app startup: + +{{< code-block lang="csharp" >}} +var client = DdFlags.CreateClient(); // Creates the default client +{{< /code-block >}} + +You can also create multiple clients by providing the `name` parameter: + +{{< code-block lang="csharp" >}} +var checkoutClient = DdFlags.CreateClient("checkout"); +{{< /code-block >}} + +
If a client with the given name already exists, the existing instance is reused.
+ +## Set the evaluation context + +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. + +{{< code-block lang="csharp" >}} +client.SetEvaluationContext( + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" } + } + ), + onComplete: success => + { + if (success) + { + Debug.Log("Flags loaded successfully!"); + } + } +); +{{< /code-block >}} + +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 once the background operation completes. + +## Evaluate flags + +After creating the `FlagsClient` and setting its evaluation context, you can start reading 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. + +### Boolean flags + +Use `GetBooleanValue(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: + +{{< code-block lang="csharp" >}} +var isNewCheckoutEnabled = client.GetBooleanValue( + key: "checkout.new", + defaultValue: false +); + +if (isNewCheckoutEnabled) +{ + ShowNewCheckoutFlow(); +} +else +{ + ShowLegacyCheckout(); +} +{{< /code-block >}} + +### String flags + +Use `GetStringValue(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: + +{{< code-block lang="csharp" >}} +var theme = client.GetStringValue( + key: "ui.theme", + defaultValue: "light" +); + +switch (theme) +{ + case "light": + SetLightTheme(); + break; + case "dark": + SetDarkTheme(); + break; + default: + SetLightTheme(); + break; +} +{{< /code-block >}} + +### Integer and double flags + +For numeric flags, use `GetIntegerValue(key, defaultValue)` or `GetDoubleValue(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: + +{{< code-block lang="csharp" >}} +var maxItems = client.GetIntegerValue( + key: "cart.items.max", + defaultValue: 20 +); + +var priceMultiplier = client.GetDoubleValue( + key: "pricing.multiplier", + defaultValue: 1.0 +); +{{< /code-block >}} + +### Object flags + +For structured or JSON-like data, use `GetObjectValue(key, defaultValue)`. This method returns an `object`, which can be cast to the appropriate type (such as a dictionary or custom class). Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: + +{{< code-block lang="csharp" >}} +var config = client.GetObjectValue( + key: "ui.config", + defaultValue: new Dictionary + { + { "color", "#00A3FF" }, + { "fontSize", 14 } + } +); + +if (config is Dictionary configDict) +{ + var color = configDict["color"] as string; + var fontSize = (int)configDict["fontSize"]; +} +{{< /code-block >}} + +### Flag evaluation details + +When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: + +* `GetBooleanDetails(key, defaultValue)` -> `FlagDetails` +* `GetStringDetails(key, defaultValue)` -> `FlagDetails` +* `GetIntegerDetails(key, defaultValue)` -> `FlagDetails` +* `GetDoubleDetails(key, defaultValue)` -> `FlagDetails` +* `GetDetails(key, defaultValue)` -> `FlagDetails` + +For example: + +{{< code-block lang="csharp" >}} +var details = client.GetStringDetails( + key: "paywall.layout", + defaultValue: "control" +); + +Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") +Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable +Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") +Debug.Log($"Error: {details.Error}"); // The error that occurred during evaluation, if any +{{< /code-block >}} + +Flag details may help you debug evaluation behavior and understand why a user received a given value. + +## Advanced configuration + +The `DdFlags.Enable()` API accepts optional configuration with options listed below. + +{{< code-block lang="csharp" >}} +var config = new FlagsConfiguration +{ + // configure options here +}; + +DdFlags.Enable(config); +{{< /code-block >}} + +`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. Set to `false` to disable exposure tracking. + +`TrackEvaluations` +: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. + +`EvaluationFlushIntervalSeconds` +: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. + +`CustomFlagsEndpoint` +: Configures a custom server URL for retrieving flag assignments. + +`CustomExposureEndpoint` +: Configures a custom server URL for sending flags exposure data. + +`CustomEvaluationEndpoint` +: Configures a custom server URL for sending flags evaluation telemetry. + +## Further reading + +{{< partial name="whats-next/whats-next.html" >}} + +[1]: https://github.com/googlesamples/unity-jar-resolver +[2]: https://openupm.com/packages/com.google.external-dependency-manager/ +[3]: https://github.com/DataDog/unity-package +[4]: https://docs.unity3d.com/Manual/gradle-templates.html +[5]: /real_user_monitoring/application_monitoring/unity/setup diff --git a/layouts/partials/feature_flags/feature_flags_client.html b/layouts/partials/feature_flags/feature_flags_client.html index 3d61897bc3c..d9001cb2bb9 100644 --- a/layouts/partials/feature_flags/feature_flags_client.html +++ b/layouts/partials/feature_flags/feature_flags_client.html @@ -65,6 +65,13 @@ + From cac19fca6015e3c5dd6ad6fffd26a12809e8c048 Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 17 Mar 2026 12:19:31 -0600 Subject: [PATCH 02/18] Simplify Unity Feature Flags docs to placeholders Replace full documentation with minimal placeholder pages to test CI: - Keep navigation links and cross-references - Add 'Documentation coming soon' message - Reduce from ~270 lines to ~28 lines each - Test if minimal changes pass all CI checks Full documentation will be added incrementally after CI validation. --- .../feature_flags/client/unity-openfeature.md | 253 +----------------- content/en/feature_flags/client/unity.md | 241 +---------------- 2 files changed, 2 insertions(+), 492 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index 408944dfc89..3c8cdab6475 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -10,9 +10,6 @@ further_reading: - link: "/real_user_monitoring/application_monitoring/unity/" tag: "Documentation" text: "Unity Monitoring" -- link: "https://github.com/DataDog/dd-sdk-unity" - tag: "Source Code" - text: "dd-sdk-unity source code" --- {{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} @@ -23,256 +20,8 @@ Feature Flags are in Preview. Complete the form to request access. ## Overview -This page describes how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. Datadog feature flags provide a unified way to remotely control feature availability in your app, experiment safely, and deliver new experiences with confidence. - -This guide explains how to install and enable the SDK, create and use a flags client with OpenFeature, and configure advanced options. - -## Installation - -Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. - -1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. - -2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. - -3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. - -4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: - - ```groovy - constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { - because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") - } - } - ``` - -## Initialize the SDK - -Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. - -For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. - -## Enable flags - -After initializing Datadog, enable flags in your application code: - -{{< code-block lang="csharp" >}} -using Datadog.Unity; -using Datadog.Unity.Flags; - -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, -}); -{{< /code-block >}} - -You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). - -## Create and retrieve a client - -Create a client once, typically during app startup: - -{{< code-block lang="csharp" >}} -DdFlags.CreateClient(); // Creates the default client -{{< /code-block >}} - -Retrieve the same client anywhere in your app using the OpenFeature API: - -{{< code-block lang="csharp" >}} -using OpenFeature; - -var client = Api.Instance.GetClient(); -{{< /code-block >}} - -You can also create and retrieve multiple clients by providing the `name` parameter: - -{{< code-block lang="csharp" >}} -DdFlags.CreateClient("checkout"); -var client = Api.Instance.GetClient("checkout"); -{{< /code-block >}} - -
If a client with the given name already exists, the existing instance is reused.
- -## Set the evaluation context - -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. - -{{< code-block lang="csharp" >}} -DdFlags.SetEvaluationContext( - new FlagsEvaluationContext( - targetingKey: "user-123", - attributes: new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" } - } - ), - onComplete: success => - { - if (success) - { - Debug.Log("Flags loaded successfully!"); - } - } -); -{{< /code-block >}} - -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 once the background operation completes. - -## Evaluate flags - -After creating the client and setting its evaluation context, you can start reading 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. - -The Unity SDK uses the [OpenFeature][6] standard API for flag evaluation. - -### Boolean flags - -Use `GetBooleanValueAsync(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: - -{{< code-block lang="csharp" >}} -var client = Api.Instance.GetClient(); - -var isNewCheckoutEnabled = await client.GetBooleanValueAsync( - flagKey: "checkout.new", - defaultValue: false -); - -if (isNewCheckoutEnabled) -{ - ShowNewCheckoutFlow(); -} -else -{ - ShowLegacyCheckout(); -} -{{< /code-block >}} - -### String flags - -Use `GetStringValueAsync(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: - -{{< code-block lang="csharp" >}} -var theme = await client.GetStringValueAsync( - flagKey: "ui.theme", - defaultValue: "light" -); - -switch (theme) -{ - case "light": - SetLightTheme(); - break; - case "dark": - SetDarkTheme(); - break; - default: - SetLightTheme(); - break; -} -{{< /code-block >}} - -### Integer and double flags - -For numeric flags, use `GetIntegerValueAsync(key, defaultValue)` or `GetDoubleValueAsync(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: - -{{< code-block lang="csharp" >}} -var maxItems = await client.GetIntegerValueAsync( - flagKey: "cart.items.max", - defaultValue: 20 -); - -var priceMultiplier = await client.GetDoubleValueAsync( - flagKey: "pricing.multiplier", - defaultValue: 1.0 -); -{{< /code-block >}} - -### Object flags - -For structured or JSON-like data, use `GetObjectValueAsync(key, defaultValue)`. This method returns an OpenFeature `Value` object, which can represent primitives, arrays, or dictionaries. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: - -{{< code-block lang="csharp" >}} -var config = await client.GetObjectValueAsync( - flagKey: "ui.config", - defaultValue: new Value(new Structure(new Dictionary - { - { "color", new Value("#00A3FF") }, - { "fontSize", new Value(14) } - })) -); - -var color = config.AsStructure["color"].AsString; -var fontSize = config.AsStructure["fontSize"].AsInteger; -{{< /code-block >}} - -### Flag evaluation details - -When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: - -* `GetBooleanDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetStringDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetIntegerDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetDoubleDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetObjectDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` - -For example: - -{{< code-block lang="csharp" >}} -var details = await client.GetStringDetailsAsync( - flagKey: "paywall.layout", - defaultValue: "control" -); - -Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") -Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable -Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") -Debug.Log($"ErrorType: {details.ErrorType}"); // The error that occurred during evaluation, if any -{{< /code-block >}} - -Flag details may help you debug evaluation behavior and understand why a user received a given value. - -## Advanced configuration - -The `DdFlags.Enable()` API accepts optional configuration with options listed below. - -{{< code-block lang="csharp" >}} -var config = new FlagsConfiguration -{ - // configure options here -}; - -DdFlags.Enable(config); -{{< /code-block >}} - -`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. Set to `false` to disable exposure tracking. - -`TrackEvaluations` -: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. - -`EvaluationFlushIntervalSeconds` -: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. - -`CustomFlagsEndpoint` -: Configures a custom server URL for retrieving flag assignments. - -`CustomExposureEndpoint` -: Configures a custom server URL for sending flags exposure data. - -`CustomEvaluationEndpoint` -: Configures a custom server URL for sending flags evaluation telemetry. +Documentation coming soon. This page will describe how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. ## Further reading {{< partial name="whats-next/whats-next.html" >}} - -[1]: https://github.com/googlesamples/unity-jar-resolver -[2]: https://openupm.com/packages/com.google.external-dependency-manager/ -[3]: https://github.com/DataDog/unity-package -[4]: https://docs.unity3d.com/Manual/gradle-templates.html -[5]: /real_user_monitoring/application_monitoring/unity/setup -[6]: https://openfeature.dev/ diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 83780ba0f49..2138d71268c 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -10,9 +10,6 @@ further_reading: - link: "/real_user_monitoring/application_monitoring/unity/" tag: "Documentation" text: "Unity Monitoring" -- link: "https://github.com/DataDog/dd-sdk-unity" - tag: "Source Code" - text: "dd-sdk-unity source code" --- {{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} @@ -23,244 +20,8 @@ Feature Flags are in Preview. Complete the form to request access. ## Overview -This page describes how to instrument your Unity 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. - -This guide explains how to install and enable the SDK, create and use a `FlagsClient`, and configure advanced options. - -## Installation - -Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. - -1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. - -2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. - -3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. - -4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: - - ```groovy - constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { - because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") - } - } - ``` - -## Initialize the SDK - -Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. - -For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. - -## Enable flags - -After initializing Datadog, enable flags in your application code: - -{{< code-block lang="csharp" >}} -using Datadog.Unity.Flags; - -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, -}); -{{< /code-block >}} - -You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). - -## Create and retrieve a client - -Create a client once, typically during app startup: - -{{< code-block lang="csharp" >}} -var client = DdFlags.CreateClient(); // Creates the default client -{{< /code-block >}} - -You can also create multiple clients by providing the `name` parameter: - -{{< code-block lang="csharp" >}} -var checkoutClient = DdFlags.CreateClient("checkout"); -{{< /code-block >}} - -
If a client with the given name already exists, the existing instance is reused.
- -## Set the evaluation context - -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. - -{{< code-block lang="csharp" >}} -client.SetEvaluationContext( - new FlagsEvaluationContext( - targetingKey: "user-123", - attributes: new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" } - } - ), - onComplete: success => - { - if (success) - { - Debug.Log("Flags loaded successfully!"); - } - } -); -{{< /code-block >}} - -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 once the background operation completes. - -## Evaluate flags - -After creating the `FlagsClient` and setting its evaluation context, you can start reading 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. - -### Boolean flags - -Use `GetBooleanValue(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: - -{{< code-block lang="csharp" >}} -var isNewCheckoutEnabled = client.GetBooleanValue( - key: "checkout.new", - defaultValue: false -); - -if (isNewCheckoutEnabled) -{ - ShowNewCheckoutFlow(); -} -else -{ - ShowLegacyCheckout(); -} -{{< /code-block >}} - -### String flags - -Use `GetStringValue(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: - -{{< code-block lang="csharp" >}} -var theme = client.GetStringValue( - key: "ui.theme", - defaultValue: "light" -); - -switch (theme) -{ - case "light": - SetLightTheme(); - break; - case "dark": - SetDarkTheme(); - break; - default: - SetLightTheme(); - break; -} -{{< /code-block >}} - -### Integer and double flags - -For numeric flags, use `GetIntegerValue(key, defaultValue)` or `GetDoubleValue(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: - -{{< code-block lang="csharp" >}} -var maxItems = client.GetIntegerValue( - key: "cart.items.max", - defaultValue: 20 -); - -var priceMultiplier = client.GetDoubleValue( - key: "pricing.multiplier", - defaultValue: 1.0 -); -{{< /code-block >}} - -### Object flags - -For structured or JSON-like data, use `GetObjectValue(key, defaultValue)`. This method returns an `object`, which can be cast to the appropriate type (such as a dictionary or custom class). Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: - -{{< code-block lang="csharp" >}} -var config = client.GetObjectValue( - key: "ui.config", - defaultValue: new Dictionary - { - { "color", "#00A3FF" }, - { "fontSize", 14 } - } -); - -if (config is Dictionary configDict) -{ - var color = configDict["color"] as string; - var fontSize = (int)configDict["fontSize"]; -} -{{< /code-block >}} - -### Flag evaluation details - -When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: - -* `GetBooleanDetails(key, defaultValue)` -> `FlagDetails` -* `GetStringDetails(key, defaultValue)` -> `FlagDetails` -* `GetIntegerDetails(key, defaultValue)` -> `FlagDetails` -* `GetDoubleDetails(key, defaultValue)` -> `FlagDetails` -* `GetDetails(key, defaultValue)` -> `FlagDetails` - -For example: - -{{< code-block lang="csharp" >}} -var details = client.GetStringDetails( - key: "paywall.layout", - defaultValue: "control" -); - -Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") -Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable -Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") -Debug.Log($"Error: {details.Error}"); // The error that occurred during evaluation, if any -{{< /code-block >}} - -Flag details may help you debug evaluation behavior and understand why a user received a given value. - -## Advanced configuration - -The `DdFlags.Enable()` API accepts optional configuration with options listed below. - -{{< code-block lang="csharp" >}} -var config = new FlagsConfiguration -{ - // configure options here -}; - -DdFlags.Enable(config); -{{< /code-block >}} - -`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. Set to `false` to disable exposure tracking. - -`TrackEvaluations` -: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. - -`EvaluationFlushIntervalSeconds` -: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. - -`CustomFlagsEndpoint` -: Configures a custom server URL for retrieving flag assignments. - -`CustomExposureEndpoint` -: Configures a custom server URL for sending flags exposure data. - -`CustomEvaluationEndpoint` -: Configures a custom server URL for sending flags evaluation telemetry. +Documentation coming soon. This page will describe how to instrument your Unity application with the Datadog Feature Flags SDK using the direct FlagsClient API. ## Further reading {{< partial name="whats-next/whats-next.html" >}} - -[1]: https://github.com/googlesamples/unity-jar-resolver -[2]: https://openupm.com/packages/com.google.external-dependency-manager/ -[3]: https://github.com/DataDog/unity-package -[4]: https://docs.unity3d.com/Manual/gradle-templates.html -[5]: /real_user_monitoring/application_monitoring/unity/setup From 295d7a97879e7bdc305d90028cdf6c7b139b36ae Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 17 Mar 2026 13:44:50 -0600 Subject: [PATCH 03/18] Add Overview, Installation, and Initialize SDK sections to OpenFeature docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Incremental update to unity-openfeature.md: - Add detailed Overview explaining OpenFeature integration - Add complete Installation instructions (EDM4U, Unity package, Android setup) - Add Initialize SDK section with reference to Unity Monitoring Setup - Add reference links at bottom File size: 27 → 68 lines (+41 lines) --- .../feature_flags/client/unity-openfeature.md | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index 3c8cdab6475..349dfbad2eb 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -20,8 +20,44 @@ Feature Flags are in Preview. Complete the form to request access. ## Overview -Documentation coming soon. This page will describe how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. +This page describes how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. Datadog feature flags provide a unified way to remotely control feature availability in your app, experiment safely, and deliver new experiences with confidence. + +This guide explains how to install and enable the SDK, create and use a flags client with OpenFeature, and configure advanced options. + +## Installation + +Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. + +1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. + +2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. + +3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. + +4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: + + ```groovy + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } + ``` + +## Initialize the SDK + +Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. + +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. ## Further reading {{< partial name="whats-next/whats-next.html" >}} + +[1]: https://github.com/googlesamples/unity-jar-resolver +[2]: https://openupm.com/packages/com.google.external-dependency-manager/ +[3]: https://github.com/DataDog/unity-package +[4]: https://docs.unity3d.com/Manual/gradle-templates.html +[5]: /real_user_monitoring/application_monitoring/unity/setup + +{{< partial name="whats-next/whats-next.html" >}} From 18c83ffb678dde7a5df01a0744c31fb45824887e Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 17 Mar 2026 15:41:49 -0600 Subject: [PATCH 04/18] Restore full OpenFeature docs for Unity Feature Flags Add back all sections to unity-openfeature.md: - Enable flags - Create and retrieve a client - Set the evaluation context - Evaluate flags (boolean, string, integer, double, object) - Flag evaluation details - Advanced configuration Also fixes duplicate further_reading partial and adds OpenFeature external link to further_reading frontmatter. --- .../feature_flags/client/unity-openfeature.md | 221 +++++++++++++++++- 1 file changed, 219 insertions(+), 2 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index 349dfbad2eb..b919cb95844 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -10,6 +10,12 @@ further_reading: - link: "/real_user_monitoring/application_monitoring/unity/" tag: "Documentation" text: "Unity Monitoring" +- link: "https://github.com/DataDog/dd-sdk-unity" + tag: "Source Code" + text: "dd-sdk-unity source code" +- link: "https://openfeature.dev/" + tag: "External" + text: "OpenFeature" --- {{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} @@ -50,6 +56,218 @@ Initialize Datadog as early as possible in your app lifecycle. Navigate to your For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. +## Enable flags + +After initializing Datadog, enable flags in your application code: + +{{< code-block lang="csharp" >}} +using Datadog.Unity.Flags; + +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, +}); +{{< /code-block >}} + +You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). + +## Create and retrieve a client + +Create a client once, typically during app startup: + +{{< code-block lang="csharp" >}} +DdFlags.CreateClient(); // Creates the default client +{{< /code-block >}} + +Retrieve the same client anywhere in your app using the OpenFeature API: + +{{< code-block lang="csharp" >}} +using OpenFeature; + +var client = Api.Instance.GetClient(); +{{< /code-block >}} + +You can also create and retrieve multiple clients by providing the `name` parameter: + +{{< code-block lang="csharp" >}} +DdFlags.CreateClient("checkout"); +var client = Api.Instance.GetClient("checkout"); +{{< /code-block >}} + +
If a client with the given name already exists, the existing instance is reused.
+ +## Set the evaluation context + +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. + +{{< code-block lang="csharp" >}} +DdFlags.SetEvaluationContext( + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" } + } + ), + onComplete: success => + { + if (success) + { + Debug.Log("Flags loaded successfully!"); + } + } +); +{{< /code-block >}} + +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 once the background operation completes. + +## Evaluate flags + +After creating the client and setting its evaluation context, you can start reading 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. + +The Unity SDK uses the [OpenFeature][6] standard API for flag evaluation. + +### Boolean flags + +Use `GetBooleanValueAsync(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: + +{{< code-block lang="csharp" >}} +var client = Api.Instance.GetClient(); + +var isNewCheckoutEnabled = await client.GetBooleanValueAsync( + flagKey: "checkout.new", + defaultValue: false +); + +if (isNewCheckoutEnabled) +{ + ShowNewCheckoutFlow(); +} +else +{ + ShowLegacyCheckout(); +} +{{< /code-block >}} + +### String flags + +Use `GetStringValueAsync(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: + +{{< code-block lang="csharp" >}} +var theme = await client.GetStringValueAsync( + flagKey: "ui.theme", + defaultValue: "light" +); + +switch (theme) +{ + case "light": + SetLightTheme(); + break; + case "dark": + SetDarkTheme(); + break; + default: + SetLightTheme(); + break; +} +{{< /code-block >}} + +### Integer and double flags + +For numeric flags, use `GetIntegerValueAsync(key, defaultValue)` or `GetDoubleValueAsync(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: + +{{< code-block lang="csharp" >}} +var maxItems = await client.GetIntegerValueAsync( + flagKey: "cart.items.max", + defaultValue: 20 +); + +var priceMultiplier = await client.GetDoubleValueAsync( + flagKey: "pricing.multiplier", + defaultValue: 1.0 +); +{{< /code-block >}} + +### Object flags + +For structured or JSON-like data, use `GetObjectValueAsync(key, defaultValue)`. This method returns an OpenFeature `Value` object, which can represent primitives, arrays, or dictionaries. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: + +{{< code-block lang="csharp" >}} +var config = await client.GetObjectValueAsync( + flagKey: "ui.config", + defaultValue: new Value(new Structure(new Dictionary + { + { "color", new Value("#00A3FF") }, + { "fontSize", new Value(14) } + })) +); + +var color = config.AsStructure["color"].AsString; +var fontSize = config.AsStructure["fontSize"].AsInteger; +{{< /code-block >}} + +### Flag evaluation details + +When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: + +* `GetBooleanDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetStringDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetIntegerDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetDoubleDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` +* `GetObjectDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` + +For example: + +{{< code-block lang="csharp" >}} +var details = await client.GetStringDetailsAsync( + flagKey: "paywall.layout", + defaultValue: "control" +); + +Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") +Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable +Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") +Debug.Log($"ErrorType: {details.ErrorType}"); // The error that occurred during evaluation, if any +{{< /code-block >}} + +Flag details may help you debug evaluation behavior and understand why a user received a given value. + +## Advanced configuration + +The `DdFlags.Enable()` API accepts optional configuration with options listed below. + +{{< code-block lang="csharp" >}} +var config = new FlagsConfiguration +{ + // configure options here +}; + +DdFlags.Enable(config); +{{< /code-block >}} + +`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. Set to `false` to disable exposure tracking. + +`TrackEvaluations` +: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. + +`EvaluationFlushIntervalSeconds` +: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. + +`CustomFlagsEndpoint` +: Configures a custom server URL for retrieving flag assignments. + +`CustomExposureEndpoint` +: Configures a custom server URL for sending flags exposure data. + +`CustomEvaluationEndpoint` +: Configures a custom server URL for sending flags evaluation telemetry. + ## Further reading {{< partial name="whats-next/whats-next.html" >}} @@ -59,5 +277,4 @@ For more information about setting up the Unity SDK, see [Unity Monitoring Setup [3]: https://github.com/DataDog/unity-package [4]: https://docs.unity3d.com/Manual/gradle-templates.html [5]: /real_user_monitoring/application_monitoring/unity/setup - -{{< partial name="whats-next/whats-next.html" >}} +[6]: https://openfeature.dev/ From 4e7a1c9dd95d09dcf1e9fbe97268d509acb14e5c Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 17 Mar 2026 16:06:41 -0600 Subject: [PATCH 05/18] Restore full Unity Feature Flags direct API documentation Add back all sections to unity.md: - Overview - Installation - Initialize the SDK - Enable flags - Create and retrieve a client - Set the evaluation context - Evaluate flags (boolean, string, integer, double, object) - Flag evaluation details - Advanced configuration --- content/en/feature_flags/client/unity.md | 241 ++++++++++++++++++++++- 1 file changed, 240 insertions(+), 1 deletion(-) diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 2138d71268c..71922df04e5 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -10,6 +10,9 @@ further_reading: - link: "/real_user_monitoring/application_monitoring/unity/" tag: "Documentation" text: "Unity Monitoring" +- link: "https://github.com/DataDog/dd-sdk-unity" + tag: "Source Code" + text: "dd-sdk-unity source code" --- {{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} @@ -20,8 +23,244 @@ Feature Flags are in Preview. Complete the form to request access. ## Overview -Documentation coming soon. This page will describe how to instrument your Unity application with the Datadog Feature Flags SDK using the direct FlagsClient API. +This page describes how to instrument your Unity 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. + +This guide explains how to install and enable the SDK, create and use a `FlagsClient`, and configure advanced options. + +## Installation + +Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. + +1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. + +2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. + +3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. + +4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: + + ```groovy + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } + ``` + +## Initialize the SDK + +Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. + +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. + +## Enable flags + +After initializing Datadog, enable flags in your application code: + +{{< code-block lang="csharp" >}} +using Datadog.Unity.Flags; + +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, +}); +{{< /code-block >}} + +You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). + +## Create and retrieve a client + +Create a client once, typically during app startup, and hold a reference to it: + +{{< code-block lang="csharp" >}} +var client = DdFlags.CreateClient(); // Creates the default client +{{< /code-block >}} + +You can also create multiple clients by providing the `name` parameter: + +{{< code-block lang="csharp" >}} +var checkoutClient = DdFlags.CreateClient("checkout"); +{{< /code-block >}} + +
If a client with the given name already exists, the existing instance is reused.
+ +## Set the evaluation context + +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. + +{{< code-block lang="csharp" >}} +client.SetEvaluationContext( + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" } + } + ), + onComplete: success => + { + if (success) + { + Debug.Log("Flags loaded successfully!"); + } + } +); +{{< /code-block >}} + +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 once the background operation completes. + +## Evaluate flags + +After creating the `FlagsClient` and setting its evaluation context, you can start reading 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. + +### Boolean flags + +Use `GetBooleanValue(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: + +{{< code-block lang="csharp" >}} +var isNewCheckoutEnabled = client.GetBooleanValue( + key: "checkout.new", + defaultValue: false +); + +if (isNewCheckoutEnabled) +{ + ShowNewCheckoutFlow(); +} +else +{ + ShowLegacyCheckout(); +} +{{< /code-block >}} + +### String flags + +Use `GetStringValue(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: + +{{< code-block lang="csharp" >}} +var theme = client.GetStringValue( + key: "ui.theme", + defaultValue: "light" +); + +switch (theme) +{ + case "light": + SetLightTheme(); + break; + case "dark": + SetDarkTheme(); + break; + default: + SetLightTheme(); + break; +} +{{< /code-block >}} + +### Integer and double flags + +For numeric flags, use `GetIntegerValue(key, defaultValue)` or `GetDoubleValue(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: + +{{< code-block lang="csharp" >}} +var maxItems = client.GetIntegerValue( + key: "cart.items.max", + defaultValue: 20 +); + +var priceMultiplier = client.GetDoubleValue( + key: "pricing.multiplier", + defaultValue: 1.0 +); +{{< /code-block >}} + +### Object flags + +For structured or JSON-like data, use `GetObjectValue(key, defaultValue)`. This method returns an `object`, which can be cast to the appropriate type. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: + +{{< code-block lang="csharp" >}} +var config = client.GetObjectValue( + key: "ui.config", + defaultValue: new Dictionary + { + { "color", "#00A3FF" }, + { "fontSize", 14 } + } +); + +if (config is Dictionary configDict) +{ + var color = configDict["color"] as string; + var fontSize = (int)configDict["fontSize"]; +} +{{< /code-block >}} + +### Flag evaluation details + +When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: + +* `GetBooleanDetails(key, defaultValue)` -> `FlagDetails` +* `GetStringDetails(key, defaultValue)` -> `FlagDetails` +* `GetIntegerDetails(key, defaultValue)` -> `FlagDetails` +* `GetDoubleDetails(key, defaultValue)` -> `FlagDetails` +* `GetDetails(key, defaultValue)` -> `FlagDetails` + +For example: + +{{< code-block lang="csharp" >}} +var details = client.GetStringDetails( + key: "paywall.layout", + defaultValue: "control" +); + +Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") +Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable +Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") +Debug.Log($"Error: {details.Error}"); // The error that occurred during evaluation, if any +{{< /code-block >}} + +Flag details may help you debug evaluation behavior and understand why a user received a given value. + +## Advanced configuration + +The `DdFlags.Enable()` API accepts optional configuration with options listed below. + +{{< code-block lang="csharp" >}} +var config = new FlagsConfiguration +{ + // configure options here +}; + +DdFlags.Enable(config); +{{< /code-block >}} + +`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. Set to `false` to disable exposure tracking. + +`TrackEvaluations` +: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. + +`EvaluationFlushIntervalSeconds` +: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. + +`CustomFlagsEndpoint` +: Configures a custom server URL for retrieving flag assignments. + +`CustomExposureEndpoint` +: Configures a custom server URL for sending flags exposure data. + +`CustomEvaluationEndpoint` +: Configures a custom server URL for sending flags evaluation telemetry. ## Further reading {{< partial name="whats-next/whats-next.html" >}} + +[1]: https://github.com/googlesamples/unity-jar-resolver +[2]: https://openupm.com/packages/com.google.external-dependency-manager/ +[3]: https://github.com/DataDog/unity-package +[4]: https://docs.unity3d.com/Manual/gradle-templates.html +[5]: /real_user_monitoring/application_monitoring/unity/setup From 5e10195e3955ee6bcfd1000c256a42c55c56e5e5 Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 17 Mar 2026 22:17:13 -0600 Subject: [PATCH 06/18] Remove preview callout from Unity Feature Flags docs Feature flags are no longer in preview. Removed the callout from both unity.md and unity-openfeature.md to match the other SDK pages (android, ios, javascript, react). --- content/en/feature_flags/client/unity-openfeature.md | 4 ---- content/en/feature_flags/client/unity.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index b919cb95844..76e50823106 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -18,10 +18,6 @@ further_reading: text: "OpenFeature" --- -{{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} -Feature Flags are in Preview. Complete the form to request access. -{{< /callout >}} -
This page documents the OpenFeature integration for Unity Feature Flags. For the direct FlagsClient API (without OpenFeature), see Unity Feature Flags.
## Overview diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 71922df04e5..20c952dee06 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -15,10 +15,6 @@ further_reading: text: "dd-sdk-unity source code" --- -{{< callout url="http://datadoghq.com/product-preview/feature-flags/" >}} -Feature Flags are in Preview. Complete the form to request access. -{{< /callout >}} -
This page documents the direct FlagsClient API for Unity Feature Flags. If you're looking for OpenFeature integration, see Unity Feature Flags (OpenFeature).
## Overview From 795df94b08ea5d8c3f4cc20743f23be28af4eca2 Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Thu, 19 Mar 2026 12:17:55 -0600 Subject: [PATCH 07/18] Update Unity Feature Flags docs with correct API and Getting Started section - FlagsConfiguration is now immutable (constructor-based, not object initializer) - Add Getting Started quickstart section to unity.md - Fix DdFlags.Instance.CreateClient() throughout unity.md - Update parameter names to match constructor signatures (camelCase) - Add EvaluationFlushIntervalSeconds clamp range [1, 60] to both pages --- .../feature_flags/client/unity-openfeature.md | 34 +++--- content/en/feature_flags/client/unity.md | 108 +++++++++++------- 2 files changed, 81 insertions(+), 61 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index 76e50823106..68148c4dd55 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -59,11 +59,10 @@ After initializing Datadog, enable flags in your application code: {{< code-block lang="csharp" >}} using Datadog.Unity.Flags; -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, -}); +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true +)); {{< /code-block >}} You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). @@ -238,30 +237,29 @@ Flag details may help you debug evaluation behavior and understand why a user re The `DdFlags.Enable()` API accepts optional configuration with options listed below. {{< code-block lang="csharp" >}} -var config = new FlagsConfiguration -{ - // configure options here -}; - -DdFlags.Enable(config); +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true, + evaluationFlushIntervalSeconds: 10.0f +)); {{< /code-block >}} -`TrackExposures` +`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. Set to `false` to disable exposure tracking. -`TrackEvaluations` +`trackEvaluations` : When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. -`EvaluationFlushIntervalSeconds` -: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. +`evaluationFlushIntervalSeconds` +: The interval in seconds at which batched evaluation events are sent to Datadog. Accepted values are between `1` and `60`. Default is `10.0` seconds. -`CustomFlagsEndpoint` +`customFlagsEndpoint` : Configures a custom server URL for retrieving flag assignments. -`CustomExposureEndpoint` +`customExposureEndpoint` : Configures a custom server URL for sending flags exposure data. -`CustomEvaluationEndpoint` +`customEvaluationEndpoint` : Configures a custom server URL for sending flags evaluation telemetry. ## Further reading diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 20c952dee06..338ca77c49a 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -49,6 +49,46 @@ Initialize Datadog as early as possible in your app lifecycle. Navigate to your For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. +## Getting started + +After the SDK is initialized, set up feature flags with these steps: + +{{< code-block lang="csharp" >}} +using System.Collections.Generic; +using Datadog.Unity.Flags; +using UnityEngine; + +// 1. Enable the Flags feature after Datadog SDK initialization +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true +)); + +// 2. Create a client (once, at startup) +var client = DdFlags.Instance.CreateClient(); + +// 3. Set the evaluation context (fetches flag assignments from the server) +client.SetEvaluationContext( + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" } + } + ), + onComplete: success => + { + if (success) + { + // 4. Evaluate flags — local and instantaneous + var isNewCheckoutEnabled = client.GetBooleanValue("checkout.new", false); + Debug.Log($"checkout.new = {isNewCheckoutEnabled}"); + } + } +); +{{< /code-block >}} + ## Enable flags After initializing Datadog, enable flags in your application code: @@ -56,11 +96,10 @@ After initializing Datadog, enable flags in your application code: {{< code-block lang="csharp" >}} using Datadog.Unity.Flags; -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, -}); +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true +)); {{< /code-block >}} You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). @@ -70,13 +109,13 @@ You can also pass additional configuration options; see [Advanced configuration] Create a client once, typically during app startup, and hold a reference to it: {{< code-block lang="csharp" >}} -var client = DdFlags.CreateClient(); // Creates the default client +var client = DdFlags.Instance.CreateClient(); // Creates the default client {{< /code-block >}} You can also create multiple clients by providing the `name` parameter: {{< code-block lang="csharp" >}} -var checkoutClient = DdFlags.CreateClient("checkout"); +var checkoutClient = DdFlags.Instance.CreateClient("checkout"); {{< /code-block >}}
If a client with the given name already exists, the existing instance is reused.
@@ -118,10 +157,7 @@ Each flag is identified by a _key_ (a unique string) and can be evaluated with a Use `GetBooleanValue(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: {{< code-block lang="csharp" >}} -var isNewCheckoutEnabled = client.GetBooleanValue( - key: "checkout.new", - defaultValue: false -); +var isNewCheckoutEnabled = client.GetBooleanValue("checkout.new", false); if (isNewCheckoutEnabled) { @@ -138,10 +174,7 @@ else Use `GetStringValue(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: {{< code-block lang="csharp" >}} -var theme = client.GetStringValue( - key: "ui.theme", - defaultValue: "light" -); +var theme = client.GetStringValue("ui.theme", "light"); switch (theme) { @@ -162,15 +195,8 @@ switch (theme) For numeric flags, use `GetIntegerValue(key, defaultValue)` or `GetDoubleValue(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: {{< code-block lang="csharp" >}} -var maxItems = client.GetIntegerValue( - key: "cart.items.max", - defaultValue: 20 -); - -var priceMultiplier = client.GetDoubleValue( - key: "pricing.multiplier", - defaultValue: 1.0 -); +var maxItems = client.GetIntegerValue("cart.items.max", 20); +var priceMultiplier = client.GetDoubleValue("pricing.multiplier", 1.0); {{< /code-block >}} ### Object flags @@ -179,8 +205,8 @@ For structured or JSON-like data, use `GetObjectValue(key, defaultValue)`. This {{< code-block lang="csharp" >}} var config = client.GetObjectValue( - key: "ui.config", - defaultValue: new Dictionary + "ui.config", + new Dictionary { { "color", "#00A3FF" }, { "fontSize", 14 } @@ -207,10 +233,7 @@ When you need more than just the flag value, use the detail methods. These metho For example: {{< code-block lang="csharp" >}} -var details = client.GetStringDetails( - key: "paywall.layout", - defaultValue: "control" -); +var details = client.GetStringDetails("paywall.layout", "control"); Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable @@ -225,30 +248,29 @@ Flag details may help you debug evaluation behavior and understand why a user re The `DdFlags.Enable()` API accepts optional configuration with options listed below. {{< code-block lang="csharp" >}} -var config = new FlagsConfiguration -{ - // configure options here -}; - -DdFlags.Enable(config); +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true, + evaluationFlushIntervalSeconds: 10.0f +)); {{< /code-block >}} -`TrackExposures` +`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. Set to `false` to disable exposure tracking. -`TrackEvaluations` +`trackEvaluations` : When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. -`EvaluationFlushIntervalSeconds` -: The interval in seconds at which batched evaluation events are sent to Datadog. Default is `10.0` seconds. +`evaluationFlushIntervalSeconds` +: The interval in seconds at which batched evaluation events are sent to Datadog. Accepted values are between `1` and `60`. Default is `10.0` seconds. -`CustomFlagsEndpoint` +`customFlagsEndpoint` : Configures a custom server URL for retrieving flag assignments. -`CustomExposureEndpoint` +`customExposureEndpoint` : Configures a custom server URL for sending flags exposure data. -`CustomEvaluationEndpoint` +`customEvaluationEndpoint` : Configures a custom server URL for sending flags evaluation telemetry. ## Further reading From 4923c3e918cc4adb6df8c3b38d4720fbbaf603dd Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Thu, 19 Mar 2026 12:36:54 -0600 Subject: [PATCH 08/18] Fix Unity OpenFeature docs to match openfeature SDK worktree - Revert FlagsConfiguration to object initializer syntax (mutable properties, PascalCase) - Restore DdFlags.SetEvaluationContext() as static method (not on client) - DdFlags.CreateClient() returns void; OpenFeature client retrieved via Api.Instance.GetClient() - Add Getting Started quickstart section - Restore correct advanced config property names (PascalCase) --- .../feature_flags/client/unity-openfeature.md | 75 +++++++++++++++---- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index 68148c4dd55..fa2a922a583 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -52,6 +52,49 @@ Initialize Datadog as early as possible in your app lifecycle. Navigate to your For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. +## Getting started + +After the SDK is initialized, set up feature flags with these steps: + +{{< code-block lang="csharp" >}} +using System.Collections.Generic; +using Datadog.Unity.Flags; +using OpenFeature; +using UnityEngine; + +// 1. Enable the Flags feature after Datadog SDK initialization +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, +}); + +// 2. Create the default client (wires up the OpenFeature provider automatically) +DdFlags.CreateClient(); + +// 3. Set the evaluation context (fetches flag assignments from the server) +DdFlags.SetEvaluationContext( + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" } + } + ), + onComplete: async success => + { + if (success) + { + // 4. Evaluate flags via the OpenFeature API + var client = Api.Instance.GetClient(); + var isNewCheckoutEnabled = await client.GetBooleanValueAsync("checkout.new", false); + Debug.Log($"checkout.new = {isNewCheckoutEnabled}"); + } + } +); +{{< /code-block >}} + ## Enable flags After initializing Datadog, enable flags in your application code: @@ -59,10 +102,11 @@ After initializing Datadog, enable flags in your application code: {{< code-block lang="csharp" >}} using Datadog.Unity.Flags; -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true -)); +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, +}); {{< /code-block >}} You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). @@ -237,29 +281,30 @@ Flag details may help you debug evaluation behavior and understand why a user re The `DdFlags.Enable()` API accepts optional configuration with options listed below. {{< code-block lang="csharp" >}} -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true, - evaluationFlushIntervalSeconds: 10.0f -)); +DdFlags.Enable(new FlagsConfiguration +{ + TrackExposures = true, + TrackEvaluations = true, + EvaluationFlushIntervalSeconds = 10.0f, +}); {{< /code-block >}} -`trackExposures` +`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. Set to `false` to disable exposure tracking. -`trackEvaluations` +`TrackEvaluations` : When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. -`evaluationFlushIntervalSeconds` +`EvaluationFlushIntervalSeconds` : The interval in seconds at which batched evaluation events are sent to Datadog. Accepted values are between `1` and `60`. Default is `10.0` seconds. -`customFlagsEndpoint` +`CustomFlagsEndpoint` : Configures a custom server URL for retrieving flag assignments. -`customExposureEndpoint` +`CustomExposureEndpoint` : Configures a custom server URL for sending flags exposure data. -`customEvaluationEndpoint` +`CustomEvaluationEndpoint` : Configures a custom server URL for sending flags evaluation telemetry. ## Further reading From 0538017b1b740301c8102c4df604f60d47284e84 Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Thu, 19 Mar 2026 12:41:58 -0600 Subject: [PATCH 09/18] Rewrite Unity OpenFeature docs to match intended API design - DdFlags is an instance class with immutable FlagsConfiguration (constructor syntax) - DdFlags.Instance.CreateProvider() returns provider for registration with OpenFeature - Provider registered via Api.Instance.SetProviderAsync(provider) - Evaluation context set via OpenFeature standard EvaluationContext.Builder() - No Datadog-specific context types or direct provider method calls - Rename "Create and retrieve a client" section to "Register the provider" --- .../feature_flags/client/unity-openfeature.md | 170 +++++++----------- 1 file changed, 68 insertions(+), 102 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index fa2a922a583..705263c1d1b 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -24,7 +24,7 @@ further_reading: This page describes how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. Datadog feature flags provide a unified way to remotely control feature availability in your app, experiment safely, and deliver new experiences with confidence. -This guide explains how to install and enable the SDK, create and use a flags client with OpenFeature, and configure advanced options. +This guide explains how to install and enable the SDK, register the Datadog OpenFeature provider, set an evaluation context, and evaluate flags. ## Installation @@ -57,42 +57,36 @@ For more information about setting up the Unity SDK, see [Unity Monitoring Setup After the SDK is initialized, set up feature flags with these steps: {{< code-block lang="csharp" >}} -using System.Collections.Generic; using Datadog.Unity.Flags; using OpenFeature; +using OpenFeature.Model; using UnityEngine; // 1. Enable the Flags feature after Datadog SDK initialization -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, -}); - -// 2. Create the default client (wires up the OpenFeature provider automatically) -DdFlags.CreateClient(); - -// 3. Set the evaluation context (fetches flag assignments from the server) -DdFlags.SetEvaluationContext( - new FlagsEvaluationContext( - targetingKey: "user-123", - attributes: new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" } - } - ), - onComplete: async success => - { - if (success) - { - // 4. Evaluate flags via the OpenFeature API - var client = Api.Instance.GetClient(); - var isNewCheckoutEnabled = await client.GetBooleanValueAsync("checkout.new", false); - Debug.Log($"checkout.new = {isNewCheckoutEnabled}"); - } - } +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true +)); + +// 2. Create the Datadog provider and register it with OpenFeature +var provider = DdFlags.Instance.CreateProvider(); +await Api.Instance.SetProviderAsync(provider); + +// 3. Get an OpenFeature client +var client = Api.Instance.GetClient(); + +// 4. Set the evaluation context +await client.SetContextAsync( + EvaluationContext.Builder() + .SetTargetingKey("user-123") + .Set("email", "user@example.com") + .Set("tier", "premium") + .Build() ); + +// 5. Evaluate flags +var isNewCheckoutEnabled = await client.GetBooleanValueAsync("checkout.new", false); +Debug.Log($"checkout.new = {isNewCheckoutEnabled}"); {{< /code-block >}} ## Enable flags @@ -102,69 +96,60 @@ After initializing Datadog, enable flags in your application code: {{< code-block lang="csharp" >}} using Datadog.Unity.Flags; -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, -}); +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true +)); {{< /code-block >}} You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). -## Create and retrieve a client +## Register the provider -Create a client once, typically during app startup: +Create the Datadog provider and register it with the OpenFeature `Api`: {{< code-block lang="csharp" >}} -DdFlags.CreateClient(); // Creates the default client +using OpenFeature; + +var provider = DdFlags.Instance.CreateProvider(); +await Api.Instance.SetProviderAsync(provider); {{< /code-block >}} -Retrieve the same client anywhere in your app using the OpenFeature API: +Retrieve a client anywhere in your app using the OpenFeature API: {{< code-block lang="csharp" >}} -using OpenFeature; - var client = Api.Instance.GetClient(); {{< /code-block >}} -You can also create and retrieve multiple clients by providing the `name` parameter: +You can also register named providers and retrieve named clients: {{< code-block lang="csharp" >}} -DdFlags.CreateClient("checkout"); +var provider = DdFlags.Instance.CreateProvider(); +await Api.Instance.SetProviderAsync("checkout", provider); var client = Api.Instance.GetClient("checkout"); {{< /code-block >}} -
If a client with the given name already exists, the existing instance is reused.
- ## Set the evaluation context -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. +Define who or what the flag evaluation applies to using an OpenFeature `EvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. {{< code-block lang="csharp" >}} -DdFlags.SetEvaluationContext( - new FlagsEvaluationContext( - targetingKey: "user-123", - attributes: new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" } - } - ), - onComplete: success => - { - if (success) - { - Debug.Log("Flags loaded successfully!"); - } - } +using OpenFeature.Model; + +await client.SetContextAsync( + EvaluationContext.Builder() + .SetTargetingKey("user-123") + .Set("email", "user@example.com") + .Set("tier", "premium") + .Build() ); {{< /code-block >}} -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 once the background operation completes. +This triggers a fetch of flag assignments from the server. Flag updates are available for subsequent evaluations once the operation completes. ## Evaluate flags -After creating the client and setting its evaluation context, you can start reading 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. +After setting the evaluation context, you can start reading 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. @@ -175,12 +160,7 @@ The Unity SDK uses the [OpenFeature][6] standard API for flag evaluation. Use `GetBooleanValueAsync(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: {{< code-block lang="csharp" >}} -var client = Api.Instance.GetClient(); - -var isNewCheckoutEnabled = await client.GetBooleanValueAsync( - flagKey: "checkout.new", - defaultValue: false -); +var isNewCheckoutEnabled = await client.GetBooleanValueAsync("checkout.new", false); if (isNewCheckoutEnabled) { @@ -197,10 +177,7 @@ else Use `GetStringValueAsync(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: {{< code-block lang="csharp" >}} -var theme = await client.GetStringValueAsync( - flagKey: "ui.theme", - defaultValue: "light" -); +var theme = await client.GetStringValueAsync("ui.theme", "light"); switch (theme) { @@ -221,15 +198,8 @@ switch (theme) For numeric flags, use `GetIntegerValueAsync(key, defaultValue)` or `GetDoubleValueAsync(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: {{< code-block lang="csharp" >}} -var maxItems = await client.GetIntegerValueAsync( - flagKey: "cart.items.max", - defaultValue: 20 -); - -var priceMultiplier = await client.GetDoubleValueAsync( - flagKey: "pricing.multiplier", - defaultValue: 1.0 -); +var maxItems = await client.GetIntegerValueAsync("cart.items.max", 20); +var priceMultiplier = await client.GetDoubleValueAsync("pricing.multiplier", 1.0); {{< /code-block >}} ### Object flags @@ -238,8 +208,8 @@ For structured or JSON-like data, use `GetObjectValueAsync(key, defaultValue)`. {{< code-block lang="csharp" >}} var config = await client.GetObjectValueAsync( - flagKey: "ui.config", - defaultValue: new Value(new Structure(new Dictionary + "ui.config", + new Value(new Structure(new Dictionary { { "color", new Value("#00A3FF") }, { "fontSize", new Value(14) } @@ -263,10 +233,7 @@ When you need more than just the flag value, use the detail methods. These metho For example: {{< code-block lang="csharp" >}} -var details = await client.GetStringDetailsAsync( - flagKey: "paywall.layout", - defaultValue: "control" -); +var details = await client.GetStringDetailsAsync("paywall.layout", "control"); Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable @@ -281,30 +248,29 @@ Flag details may help you debug evaluation behavior and understand why a user re The `DdFlags.Enable()` API accepts optional configuration with options listed below. {{< code-block lang="csharp" >}} -DdFlags.Enable(new FlagsConfiguration -{ - TrackExposures = true, - TrackEvaluations = true, - EvaluationFlushIntervalSeconds = 10.0f, -}); +DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true, + evaluationFlushIntervalSeconds: 10.0f +)); {{< /code-block >}} -`TrackExposures` +`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. Set to `false` to disable exposure tracking. -`TrackEvaluations` +`trackEvaluations` : When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. -`EvaluationFlushIntervalSeconds` +`evaluationFlushIntervalSeconds` : The interval in seconds at which batched evaluation events are sent to Datadog. Accepted values are between `1` and `60`. Default is `10.0` seconds. -`CustomFlagsEndpoint` +`customFlagsEndpoint` : Configures a custom server URL for retrieving flag assignments. -`CustomExposureEndpoint` +`customExposureEndpoint` : Configures a custom server URL for sending flags exposure data. -`CustomEvaluationEndpoint` +`customEvaluationEndpoint` : Configures a custom server URL for sending flags evaluation telemetry. ## Further reading From fac9e2b025659b3c7709faa0cc2f09b7fad06daf Mon Sep 17 00:00:00 2001 From: typotter Date: Tue, 24 Mar 2026 09:05:38 -0600 Subject: [PATCH 10/18] Fix Unity OpenFeature docs to match intended API design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Evaluation context set via client.SetEvaluationContext(FlagsEvaluationContext) not OpenFeature context builder - DdFlags.Instance.CreateClient() returns FlagsClient (held for context setting); OpenFeature client retrieved separately via Api.Instance.GetClient() - Show Unity coroutine pattern (WaitUntil) for async flag evaluation — MonoBehaviour does not support await - Fix named provider registration: Api.Instance.SetProviderAsync("domain", provider) - Add Getting Started as full MonoBehaviour example - Remove unused openfeature.dev footnote --- .../feature_flags/client/unity-openfeature.md | 169 +++++++++++------- 1 file changed, 100 insertions(+), 69 deletions(-) diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md index 705263c1d1b..65e3a3cac69 100644 --- a/content/en/feature_flags/client/unity-openfeature.md +++ b/content/en/feature_flags/client/unity-openfeature.md @@ -24,7 +24,7 @@ further_reading: This page describes how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. Datadog feature flags provide a unified way to remotely control feature availability in your app, experiment safely, and deliver new experiences with confidence. -This guide explains how to install and enable the SDK, register the Datadog OpenFeature provider, set an evaluation context, and evaluate flags. +The Datadog SDK registers a `DatadogFeatureProvider` with the OpenFeature `Api`. Configuration and evaluation context use Datadog types; all flag evaluation uses the standard OpenFeature client API. ## Installation @@ -57,36 +57,46 @@ For more information about setting up the Unity SDK, see [Unity Monitoring Setup After the SDK is initialized, set up feature flags with these steps: {{< code-block lang="csharp" >}} +using System.Collections; +using System.Collections.Generic; using Datadog.Unity.Flags; using OpenFeature; -using OpenFeature.Model; using UnityEngine; -// 1. Enable the Flags feature after Datadog SDK initialization -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true -)); - -// 2. Create the Datadog provider and register it with OpenFeature -var provider = DdFlags.Instance.CreateProvider(); -await Api.Instance.SetProviderAsync(provider); - -// 3. Get an OpenFeature client -var client = Api.Instance.GetClient(); - -// 4. Set the evaluation context -await client.SetContextAsync( - EvaluationContext.Builder() - .SetTargetingKey("user-123") - .Set("email", "user@example.com") - .Set("tier", "premium") - .Build() -); - -// 5. Evaluate flags -var isNewCheckoutEnabled = await client.GetBooleanValueAsync("checkout.new", false); -Debug.Log($"checkout.new = {isNewCheckoutEnabled}"); +public class FlagsBehavior : MonoBehaviour +{ + private IEnumerator Start() + { + // 1. Enable the Flags feature after Datadog SDK initialization + DdFlags.Enable(new FlagsConfiguration( + trackExposures: true, + trackEvaluations: true + )); + + // 2. Create a client and register the Datadog provider with OpenFeature + var client = DdFlags.Instance.CreateClient(); + var task = Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); + yield return new WaitUntil(() => task.IsCompleted); + + // 3. Set the evaluation context (fetches flag assignments from the server) + var done = false; + client.SetEvaluationContext( + new FlagsEvaluationContext("user-123", new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" }, + }), + onComplete: _ => done = true + ); + yield return new WaitUntil(() => done); + + // 4. Evaluate flags via the OpenFeature client + var ofClient = Api.Instance.GetClient(); + var evalTask = ofClient.GetBooleanValueAsync("checkout.new", false); + yield return new WaitUntil(() => evalTask.IsCompleted); + Debug.Log($"checkout.new = {evalTask.Result}"); + } +} {{< /code-block >}} ## Enable flags @@ -106,63 +116,80 @@ You can also pass additional configuration options; see [Advanced configuration] ## Register the provider -Create the Datadog provider and register it with the OpenFeature `Api`: +Create a `FlagsClient`, then create and register the Datadog provider with the OpenFeature `Api`. The client is required to set the evaluation context later: {{< code-block lang="csharp" >}} using OpenFeature; -var provider = DdFlags.Instance.CreateProvider(); -await Api.Instance.SetProviderAsync(provider); +var client = DdFlags.Instance.CreateClient(); +await Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); {{< /code-block >}} -Retrieve a client anywhere in your app using the OpenFeature API: +Retrieve the OpenFeature client anywhere in your app to evaluate flags: {{< code-block lang="csharp" >}} -var client = Api.Instance.GetClient(); +var ofClient = Api.Instance.GetClient(); {{< /code-block >}} -You can also register named providers and retrieve named clients: +You can also create named clients to scope flags to different parts of your app: {{< code-block lang="csharp" >}} -var provider = DdFlags.Instance.CreateProvider(); -await Api.Instance.SetProviderAsync("checkout", provider); -var client = Api.Instance.GetClient("checkout"); +var client = DdFlags.Instance.CreateClient("checkout"); +await Api.Instance.SetProviderAsync("checkout", DdFlags.Instance.CreateProvider("checkout")); +var ofClient = Api.Instance.GetClient("checkout"); {{< /code-block >}} ## Set the evaluation context -Define who or what the flag evaluation applies to using an OpenFeature `EvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. {{< code-block lang="csharp" >}} -using OpenFeature.Model; - -await client.SetContextAsync( - EvaluationContext.Builder() - .SetTargetingKey("user-123") - .Set("email", "user@example.com") - .Set("tier", "premium") - .Build() +client.SetEvaluationContext( + new FlagsEvaluationContext("user-123", new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" }, + }), + onComplete: success => + { + if (success) + { + Debug.Log("Flags loaded successfully!"); + } + } ); {{< /code-block >}} -This triggers a fetch of flag assignments from the server. Flag updates are available for subsequent evaluations once the operation completes. +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 once the background operation completes. ## Evaluate flags -After setting the evaluation context, you can start reading 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. +After setting the evaluation context, use the OpenFeature client to 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. + +Each flag is identified by a _key_ (a unique string). The OpenFeature client provides typed async methods for each value type. If the flag doesn't exist or cannot be evaluated, the SDK returns the provided default value. -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. +Because Unity's `MonoBehaviour` does not support `await`, use coroutines to bridge async flag evaluation: -The Unity SDK uses the [OpenFeature][6] standard API for flag evaluation. +{{< code-block lang="csharp" >}} +private IEnumerator EvaluateFlags() +{ + var ofClient = Api.Instance.GetClient(); + + var task = ofClient.GetBooleanValueAsync("checkout.new", false); + yield return new WaitUntil(() => task.IsCompleted); + Debug.Log($"checkout.new = {task.Result}"); +} +{{< /code-block >}} ### Boolean flags Use `GetBooleanValueAsync(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: {{< code-block lang="csharp" >}} -var isNewCheckoutEnabled = await client.GetBooleanValueAsync("checkout.new", false); +var task = ofClient.GetBooleanValueAsync("checkout.new", false); +yield return new WaitUntil(() => task.IsCompleted); -if (isNewCheckoutEnabled) +if (task.Result) { ShowNewCheckoutFlow(); } @@ -177,9 +204,10 @@ else Use `GetStringValueAsync(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: {{< code-block lang="csharp" >}} -var theme = await client.GetStringValueAsync("ui.theme", "light"); +var task = ofClient.GetStringValueAsync("ui.theme", "light"); +yield return new WaitUntil(() => task.IsCompleted); -switch (theme) +switch (task.Result) { case "light": SetLightTheme(); @@ -198,8 +226,12 @@ switch (theme) For numeric flags, use `GetIntegerValueAsync(key, defaultValue)` or `GetDoubleValueAsync(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: {{< code-block lang="csharp" >}} -var maxItems = await client.GetIntegerValueAsync("cart.items.max", 20); -var priceMultiplier = await client.GetDoubleValueAsync("pricing.multiplier", 1.0); +var maxItemsTask = ofClient.GetIntegerValueAsync("cart.items.max", 20); +var multiplierTask = ofClient.GetDoubleValueAsync("pricing.multiplier", 1.0); +yield return new WaitUntil(() => maxItemsTask.IsCompleted && multiplierTask.IsCompleted); + +var maxItems = maxItemsTask.Result; +var priceMultiplier = multiplierTask.Result; {{< /code-block >}} ### Object flags @@ -207,17 +239,17 @@ var priceMultiplier = await client.GetDoubleValueAsync("pricing.multiplier", 1.0 For structured or JSON-like data, use `GetObjectValueAsync(key, defaultValue)`. This method returns an OpenFeature `Value` object, which can represent primitives, arrays, or dictionaries. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: {{< code-block lang="csharp" >}} -var config = await client.GetObjectValueAsync( - "ui.config", - new Value(new Structure(new Dictionary - { - { "color", new Value("#00A3FF") }, - { "fontSize", new Value(14) } - })) -); +var defaultConfig = new Value(new Structure(new Dictionary +{ + { "color", new Value("#00A3FF") }, + { "fontSize", new Value(14) }, +})); + +var task = ofClient.GetObjectValueAsync("ui.config", defaultConfig); +yield return new WaitUntil(() => task.IsCompleted); -var color = config.AsStructure["color"].AsString; -var fontSize = config.AsStructure["fontSize"].AsInteger; +var color = task.Result.AsStructure["color"].AsString; +var fontSize = task.Result.AsStructure["fontSize"].AsInteger; {{< /code-block >}} ### Flag evaluation details @@ -233,7 +265,9 @@ When you need more than just the flag value, use the detail methods. These metho For example: {{< code-block lang="csharp" >}} -var details = await client.GetStringDetailsAsync("paywall.layout", "control"); +var task = ofClient.GetStringDetailsAsync("paywall.layout", "control"); +yield return new WaitUntil(() => task.IsCompleted); +var details = task.Result; Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable @@ -241,8 +275,6 @@ Debug.Log($"Reason: {details.Reason}"); // Description of why this value w Debug.Log($"ErrorType: {details.ErrorType}"); // The error that occurred during evaluation, if any {{< /code-block >}} -Flag details may help you debug evaluation behavior and understand why a user received a given value. - ## Advanced configuration The `DdFlags.Enable()` API accepts optional configuration with options listed below. @@ -282,4 +314,3 @@ DdFlags.Enable(new FlagsConfiguration( [3]: https://github.com/DataDog/unity-package [4]: https://docs.unity3d.com/Manual/gradle-templates.html [5]: /real_user_monitoring/application_monitoring/unity/setup -[6]: https://openfeature.dev/ From 32b11b8c1ed82fff3a9b5b6fe4eb9e92336d43ca Mon Sep 17 00:00:00 2001 From: typotter Date: Tue, 24 Mar 2026 14:31:59 -0600 Subject: [PATCH 11/18] Consolidate Unity Feature Flags into a single page - Merge unity.md and unity-openfeature.md into one page, OpenFeature-first - Add aliases for old unity-openfeature URLs - Direct FlagsClient API moved to collapsed advanced section at the bottom - Drop FlagDetails documentation (FlagDetails and FlagEvaluationError are now internal) - Flag evaluation details section uses OpenFeature FlagEvaluationDetails types only - Delete unity-openfeature.md and unity.md.bak --- .../feature_flags/client/unity-openfeature.md | 316 ----------------- content/en/feature_flags/client/unity.md | 327 +++++++++++------- 2 files changed, 197 insertions(+), 446 deletions(-) delete mode 100644 content/en/feature_flags/client/unity-openfeature.md diff --git a/content/en/feature_flags/client/unity-openfeature.md b/content/en/feature_flags/client/unity-openfeature.md deleted file mode 100644 index 65e3a3cac69..00000000000 --- a/content/en/feature_flags/client/unity-openfeature.md +++ /dev/null @@ -1,316 +0,0 @@ ---- -title: Unity Feature Flags (OpenFeature) -description: Set up Datadog Feature Flags for Unity applications using OpenFeature. -aliases: - - /feature_flags/setup/unity-openfeature/ -further_reading: -- link: "/feature_flags/client/" - tag: "Documentation" - text: "Client-Side Feature Flags" -- link: "/real_user_monitoring/application_monitoring/unity/" - tag: "Documentation" - text: "Unity Monitoring" -- link: "https://github.com/DataDog/dd-sdk-unity" - tag: "Source Code" - text: "dd-sdk-unity source code" -- link: "https://openfeature.dev/" - tag: "External" - text: "OpenFeature" ---- - -
This page documents the OpenFeature integration for Unity Feature Flags. For the direct FlagsClient API (without OpenFeature), see Unity Feature Flags.
- -## Overview - -This page describes how to instrument your Unity application with the Datadog Feature Flags SDK using the OpenFeature standard. 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 SDK registers a `DatadogFeatureProvider` with the OpenFeature `Api`. Configuration and evaluation context use Datadog types; all flag evaluation uses the standard OpenFeature client API. - -## Installation - -Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. - -1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. - -2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. - -3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. - -4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: - - ```groovy - constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { - because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") - } - } - ``` - -## Initialize the SDK - -Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. - -For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. - -## Getting started - -After the SDK is initialized, set up feature flags with these steps: - -{{< code-block lang="csharp" >}} -using System.Collections; -using System.Collections.Generic; -using Datadog.Unity.Flags; -using OpenFeature; -using UnityEngine; - -public class FlagsBehavior : MonoBehaviour -{ - private IEnumerator Start() - { - // 1. Enable the Flags feature after Datadog SDK initialization - DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true - )); - - // 2. Create a client and register the Datadog provider with OpenFeature - var client = DdFlags.Instance.CreateClient(); - var task = Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); - yield return new WaitUntil(() => task.IsCompleted); - - // 3. Set the evaluation context (fetches flag assignments from the server) - var done = false; - client.SetEvaluationContext( - new FlagsEvaluationContext("user-123", new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" }, - }), - onComplete: _ => done = true - ); - yield return new WaitUntil(() => done); - - // 4. Evaluate flags via the OpenFeature client - var ofClient = Api.Instance.GetClient(); - var evalTask = ofClient.GetBooleanValueAsync("checkout.new", false); - yield return new WaitUntil(() => evalTask.IsCompleted); - Debug.Log($"checkout.new = {evalTask.Result}"); - } -} -{{< /code-block >}} - -## Enable flags - -After initializing Datadog, enable flags in your application code: - -{{< code-block lang="csharp" >}} -using Datadog.Unity.Flags; - -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true -)); -{{< /code-block >}} - -You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). - -## Register the provider - -Create a `FlagsClient`, then create and register the Datadog provider with the OpenFeature `Api`. The client is required to set the evaluation context later: - -{{< code-block lang="csharp" >}} -using OpenFeature; - -var client = DdFlags.Instance.CreateClient(); -await Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); -{{< /code-block >}} - -Retrieve the OpenFeature client anywhere in your app to evaluate flags: - -{{< code-block lang="csharp" >}} -var ofClient = Api.Instance.GetClient(); -{{< /code-block >}} - -You can also create named clients to scope flags to different parts of your app: - -{{< code-block lang="csharp" >}} -var client = DdFlags.Instance.CreateClient("checkout"); -await Api.Instance.SetProviderAsync("checkout", DdFlags.Instance.CreateProvider("checkout")); -var ofClient = Api.Instance.GetClient("checkout"); -{{< /code-block >}} - -## Set the evaluation context - -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. - -{{< code-block lang="csharp" >}} -client.SetEvaluationContext( - new FlagsEvaluationContext("user-123", new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" }, - }), - onComplete: success => - { - if (success) - { - Debug.Log("Flags loaded successfully!"); - } - } -); -{{< /code-block >}} - -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 once the background operation completes. - -## Evaluate flags - -After setting the evaluation context, use the OpenFeature client to 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. - -Each flag is identified by a _key_ (a unique string). The OpenFeature client provides typed async methods for each value type. If the flag doesn't exist or cannot be evaluated, the SDK returns the provided default value. - -Because Unity's `MonoBehaviour` does not support `await`, use coroutines to bridge async flag evaluation: - -{{< code-block lang="csharp" >}} -private IEnumerator EvaluateFlags() -{ - var ofClient = Api.Instance.GetClient(); - - var task = ofClient.GetBooleanValueAsync("checkout.new", false); - yield return new WaitUntil(() => task.IsCompleted); - Debug.Log($"checkout.new = {task.Result}"); -} -{{< /code-block >}} - -### Boolean flags - -Use `GetBooleanValueAsync(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: - -{{< code-block lang="csharp" >}} -var task = ofClient.GetBooleanValueAsync("checkout.new", false); -yield return new WaitUntil(() => task.IsCompleted); - -if (task.Result) -{ - ShowNewCheckoutFlow(); -} -else -{ - ShowLegacyCheckout(); -} -{{< /code-block >}} - -### String flags - -Use `GetStringValueAsync(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: - -{{< code-block lang="csharp" >}} -var task = ofClient.GetStringValueAsync("ui.theme", "light"); -yield return new WaitUntil(() => task.IsCompleted); - -switch (task.Result) -{ - case "light": - SetLightTheme(); - break; - case "dark": - SetDarkTheme(); - break; - default: - SetLightTheme(); - break; -} -{{< /code-block >}} - -### Integer and double flags - -For numeric flags, use `GetIntegerValueAsync(key, defaultValue)` or `GetDoubleValueAsync(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: - -{{< code-block lang="csharp" >}} -var maxItemsTask = ofClient.GetIntegerValueAsync("cart.items.max", 20); -var multiplierTask = ofClient.GetDoubleValueAsync("pricing.multiplier", 1.0); -yield return new WaitUntil(() => maxItemsTask.IsCompleted && multiplierTask.IsCompleted); - -var maxItems = maxItemsTask.Result; -var priceMultiplier = multiplierTask.Result; -{{< /code-block >}} - -### Object flags - -For structured or JSON-like data, use `GetObjectValueAsync(key, defaultValue)`. This method returns an OpenFeature `Value` object, which can represent primitives, arrays, or dictionaries. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: - -{{< code-block lang="csharp" >}} -var defaultConfig = new Value(new Structure(new Dictionary -{ - { "color", new Value("#00A3FF") }, - { "fontSize", new Value(14) }, -})); - -var task = ofClient.GetObjectValueAsync("ui.config", defaultConfig); -yield return new WaitUntil(() => task.IsCompleted); - -var color = task.Result.AsStructure["color"].AsString; -var fontSize = task.Result.AsStructure["fontSize"].AsInteger; -{{< /code-block >}} - -### Flag evaluation details - -When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: - -* `GetBooleanDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetStringDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetIntegerDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetDoubleDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` -* `GetObjectDetailsAsync(key, defaultValue)` -> `FlagEvaluationDetails` - -For example: - -{{< code-block lang="csharp" >}} -var task = ofClient.GetStringDetailsAsync("paywall.layout", "control"); -yield return new WaitUntil(() => task.IsCompleted); -var details = task.Result; - -Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") -Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable -Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") -Debug.Log($"ErrorType: {details.ErrorType}"); // The error that occurred during evaluation, if any -{{< /code-block >}} - -## Advanced configuration - -The `DdFlags.Enable()` API accepts optional configuration with options listed below. - -{{< code-block lang="csharp" >}} -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true, - evaluationFlushIntervalSeconds: 10.0f -)); -{{< /code-block >}} - -`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. Set to `false` to disable exposure tracking. - -`trackEvaluations` -: When `true` (default), the SDK tracks flag evaluations and sends aggregated evaluation telemetry to Datadog. This enables analytics about flag usage patterns and performance. Set to `false` to disable evaluation tracking. - -`evaluationFlushIntervalSeconds` -: The interval in seconds at which batched evaluation events are sent to Datadog. Accepted values are between `1` and `60`. Default is `10.0` seconds. - -`customFlagsEndpoint` -: Configures a custom server URL for retrieving flag assignments. - -`customExposureEndpoint` -: Configures a custom server URL for sending flags exposure data. - -`customEvaluationEndpoint` -: Configures a custom server URL for sending flags evaluation telemetry. - -## Further reading - -{{< partial name="whats-next/whats-next.html" >}} - -[1]: https://github.com/googlesamples/unity-jar-resolver -[2]: https://openupm.com/packages/com.google.external-dependency-manager/ -[3]: https://github.com/DataDog/unity-package -[4]: https://docs.unity3d.com/Manual/gradle-templates.html -[5]: /real_user_monitoring/application_monitoring/unity/setup diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 338ca77c49a..ec40f70ee99 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -3,6 +3,8 @@ title: Unity Feature Flags description: Set up Datadog Feature Flags for Unity applications. aliases: - /feature_flags/setup/unity/ + - /feature_flags/setup/unity-openfeature/ + - /feature_flags/client/unity-openfeature/ further_reading: - link: "/feature_flags/client/" tag: "Documentation" @@ -13,25 +15,74 @@ further_reading: - link: "https://github.com/DataDog/dd-sdk-unity" tag: "Source Code" text: "dd-sdk-unity source code" +- link: "https://openfeature.dev/" + tag: "External" + text: "OpenFeature" --- -
This page documents the direct FlagsClient API for Unity Feature Flags. If you're looking for OpenFeature integration, see Unity Feature Flags (OpenFeature).
- ## Overview This page describes how to instrument your Unity 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. -This guide explains how to install and enable the SDK, create and use a `FlagsClient`, and configure advanced options. +The Datadog Feature Flags SDK for Unity integrates with [OpenFeature][1], an open standard for feature flag management. This guide explains how to install the SDK, register the Datadog provider, set an evaluation context, and evaluate flags in your application. + +
For most applications, the OpenFeature API is the recommended approach. If you need direct access to the underlying FlagsClient—for example, to manage the client lifecycle independently—see Direct FlagsClient integration.
+ +## Getting started + +Here's a minimal example to get feature flags working in your Unity app: + +{{< code-block lang="csharp" >}} +using System.Collections; +using System.Collections.Generic; +using Datadog.Unity.Flags; +using OpenFeature; +using UnityEngine; + +public class FlagsBehavior : MonoBehaviour +{ + private IEnumerator Start() + { + // 1. Enable the Flags feature after Datadog SDK initialization + DdFlags.Enable(new FlagsConfiguration()); + + // 2. Create a client and register the Datadog OpenFeature provider + var client = DdFlags.Instance.CreateClient(); + var providerTask = Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); + yield return new WaitUntil(() => providerTask.IsCompleted); + + // 3. Set the evaluation context + var done = false; + client.SetEvaluationContext( + new FlagsEvaluationContext("user-123", new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" }, + }), + onComplete: _ => done = true + ); + yield return new WaitUntil(() => done); + + // 4. Evaluate flags via the OpenFeature client + var ofClient = Api.Instance.GetClient(); + var flagTask = ofClient.GetBooleanValueAsync("checkout.new", false); + yield return new WaitUntil(() => flagTask.IsCompleted); + Debug.Log($"checkout.new = {flagTask.Result}"); + } +} +{{< /code-block >}} + +The rest of this guide explains each step in detail. ## Installation Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. -1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. +1. Install the [External Dependency Manager for Unity (EDM4U)][2]. This can be done using [Open UPM][3]. -2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. +2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][4]. The package URL is `https://github.com/DataDog/unity-package.git`. -3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. +3. (Android only) Configure your project to use [Gradle templates][5], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. 4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: @@ -47,47 +98,7 @@ Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. -For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. - -## Getting started - -After the SDK is initialized, set up feature flags with these steps: - -{{< code-block lang="csharp" >}} -using System.Collections.Generic; -using Datadog.Unity.Flags; -using UnityEngine; - -// 1. Enable the Flags feature after Datadog SDK initialization -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true -)); - -// 2. Create a client (once, at startup) -var client = DdFlags.Instance.CreateClient(); - -// 3. Set the evaluation context (fetches flag assignments from the server) -client.SetEvaluationContext( - new FlagsEvaluationContext( - targetingKey: "user-123", - attributes: new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" } - } - ), - onComplete: success => - { - if (success) - { - // 4. Evaluate flags — local and instantaneous - var isNewCheckoutEnabled = client.GetBooleanValue("checkout.new", false); - Debug.Log($"checkout.new = {isNewCheckoutEnabled}"); - } - } -); -{{< /code-block >}} +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][6]. ## Enable flags @@ -96,44 +107,35 @@ After initializing Datadog, enable flags in your application code: {{< code-block lang="csharp" >}} using Datadog.Unity.Flags; -DdFlags.Enable(new FlagsConfiguration( - trackExposures: true, - trackEvaluations: true -)); +DdFlags.Enable(new FlagsConfiguration()); {{< /code-block >}} -You can also pass additional configuration options; see [Advanced configuration](#advanced-configuration). +You can also pass configuration options; see [Advanced configuration](#advanced-configuration). -## Create and retrieve a client +## Register the provider -Create a client once, typically during app startup, and hold a reference to it: +Create a `FlagsClient`, then create and register the Datadog provider with the OpenFeature `Api`. You need to hold a reference to the `FlagsClient` to set the evaluation context later. {{< code-block lang="csharp" >}} -var client = DdFlags.Instance.CreateClient(); // Creates the default client -{{< /code-block >}} +using OpenFeature; -You can also create multiple clients by providing the `name` parameter: - -{{< code-block lang="csharp" >}} -var checkoutClient = DdFlags.Instance.CreateClient("checkout"); +var client = DdFlags.Instance.CreateClient(); +await Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); {{< /code-block >}} -
If a client with the given name already exists, the existing instance is reused.
+
Call CreateClient() before CreateProvider(). The provider must be bound to an existing client.
## Set the evaluation context -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. 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. {{< code-block lang="csharp" >}} client.SetEvaluationContext( - new FlagsEvaluationContext( - targetingKey: "user-123", - attributes: new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" } - } - ), + new FlagsEvaluationContext("user-123", new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" }, + }), onComplete: success => { if (success) @@ -148,18 +150,27 @@ This method fetches flag assignments from the server asynchronously in the backg ## Evaluate flags -After creating the `FlagsClient` and setting its evaluation context, you can start reading 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. +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. -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. +Each flag is identified by a _key_ (a unique string). The OpenFeature client provides typed async methods for each value type. Because Unity's `MonoBehaviour` does not support `await`, use coroutines to bridge async flag evaluation: -### Boolean flags +{{< code-block lang="csharp" >}} +private IEnumerator EvaluateFlags() +{ + var ofClient = Api.Instance.GetClient(); + var task = ofClient.GetBooleanValueAsync("checkout.new", false); + yield return new WaitUntil(() => task.IsCompleted); + Debug.Log($"checkout.new = {task.Result}"); +} +{{< /code-block >}} -Use `GetBooleanValue(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: +### Boolean flags {{< code-block lang="csharp" >}} -var isNewCheckoutEnabled = client.GetBooleanValue("checkout.new", false); +var task = ofClient.GetBooleanValueAsync("checkout.new", false); +yield return new WaitUntil(() => task.IsCompleted); -if (isNewCheckoutEnabled) +if (task.Result) { ShowNewCheckoutFlow(); } @@ -171,78 +182,60 @@ else ### String flags -Use `GetStringValue(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: - {{< code-block lang="csharp" >}} -var theme = client.GetStringValue("ui.theme", "light"); +var task = ofClient.GetStringValueAsync("ui.theme", "light"); +yield return new WaitUntil(() => task.IsCompleted); -switch (theme) +switch (task.Result) { - case "light": - SetLightTheme(); - break; - case "dark": - SetDarkTheme(); - break; - default: - SetLightTheme(); - break; + case "light": SetLightTheme(); break; + case "dark": SetDarkTheme(); break; + default: SetLightTheme(); break; } {{< /code-block >}} ### Integer and double flags -For numeric flags, use `GetIntegerValue(key, defaultValue)` or `GetDoubleValue(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: - {{< code-block lang="csharp" >}} -var maxItems = client.GetIntegerValue("cart.items.max", 20); -var priceMultiplier = client.GetDoubleValue("pricing.multiplier", 1.0); +var maxItemsTask = ofClient.GetIntegerValueAsync("cart.items.max", 20); +var multiplierTask = ofClient.GetDoubleValueAsync("pricing.multiplier", 1.0); +yield return new WaitUntil(() => maxItemsTask.IsCompleted && multiplierTask.IsCompleted); + +var maxItems = maxItemsTask.Result; +var priceMultiplier = multiplierTask.Result; {{< /code-block >}} ### Object flags -For structured or JSON-like data, use `GetObjectValue(key, defaultValue)`. This method returns an `object`, which can be cast to the appropriate type. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: - {{< code-block lang="csharp" >}} -var config = client.GetObjectValue( - "ui.config", - new Dictionary - { - { "color", "#00A3FF" }, - { "fontSize", 14 } - } -); - -if (config is Dictionary configDict) +var defaultConfig = new Value(new Structure(new Dictionary { - var color = configDict["color"] as string; - var fontSize = (int)configDict["fontSize"]; -} -{{< /code-block >}} + { "color", new Value("#00A3FF") }, + { "fontSize", new Value(14) }, +})); -### Flag evaluation details +var task = ofClient.GetObjectValueAsync("ui.config", defaultConfig); +yield return new WaitUntil(() => task.IsCompleted); -When you need more than just the flag value, use the detail methods. These methods return both the evaluated value and metadata explaining the evaluation: +var color = task.Result.AsStructure["color"].AsString; +var fontSize = task.Result.AsStructure["fontSize"].AsInteger; +{{< /code-block >}} -* `GetBooleanDetails(key, defaultValue)` -> `FlagDetails` -* `GetStringDetails(key, defaultValue)` -> `FlagDetails` -* `GetIntegerDetails(key, defaultValue)` -> `FlagDetails` -* `GetDoubleDetails(key, defaultValue)` -> `FlagDetails` -* `GetDetails(key, defaultValue)` -> `FlagDetails` +### Flag evaluation details -For example: +When you need evaluation metadata beyond the flag value, use the detail methods. These return both the value and information about why it was chosen: {{< code-block lang="csharp" >}} -var details = client.GetStringDetails("paywall.layout", "control"); - -Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") -Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable -Debug.Log($"Reason: {details.Reason}"); // Description of why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") -Debug.Log($"Error: {details.Error}"); // The error that occurred during evaluation, if any +var task = ofClient.GetStringDetailsAsync("paywall.layout", "control"); +yield return new WaitUntil(() => task.IsCompleted); +var details = task.Result; + +Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") +Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable +Debug.Log($"Reason: {details.Reason}"); // Why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") +Debug.Log($"ErrorType: {details.ErrorType}"); // Error code, if any {{< /code-block >}} -Flag details may help you debug evaluation behavior and understand why a user received a given value. - ## Advanced configuration The `DdFlags.Enable()` API accepts optional configuration with options listed below. @@ -273,12 +266,86 @@ DdFlags.Enable(new FlagsConfiguration( `customEvaluationEndpoint` : Configures a custom server URL for sending flags evaluation telemetry. +## Direct FlagsClient integration (advanced) + +For most applications, the OpenFeature API described above is the recommended approach. Use the `FlagsClient` directly only if you need to manage the evaluation context independently of the OpenFeature provider—for example, to update context without triggering a provider state transition. + +### Create and use a client + +Create and hold a reference to the `FlagsClient`: + +{{% collapse-content title="Create a client" level="h4" %}} +{{< code-block lang="csharp" >}} +var client = DdFlags.Instance.CreateClient(); +{{< /code-block >}} + +You can also create named clients: + +{{< code-block lang="csharp" >}} +var checkoutClient = DdFlags.Instance.CreateClient("checkout"); +{{< /code-block >}} + +
If a client with the given name already exists, the existing instance is reused.
+{{% /collapse-content %}} + +{{% collapse-content title="Set the evaluation context" level="h4" %}} +{{< code-block lang="csharp" >}} +client.SetEvaluationContext( + new FlagsEvaluationContext("user-123", new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" }, + }), + onComplete: success => + { + if (success) + { + Debug.Log("Flags loaded successfully!"); + } + } +); +{{< /code-block >}} +{{% /collapse-content %}} + +{{% collapse-content title="Boolean flags" level="h4" %}} +{{< code-block lang="csharp" >}} +var isEnabled = client.GetBooleanValue("checkout.new", false); +{{< /code-block >}} +{{% /collapse-content %}} + +{{% collapse-content title="String flags" level="h4" %}} +{{< code-block lang="csharp" >}} +var theme = client.GetStringValue("ui.theme", "light"); +{{< /code-block >}} +{{% /collapse-content %}} + +{{% collapse-content title="Integer and double flags" level="h4" %}} +{{< code-block lang="csharp" >}} +var maxItems = client.GetIntegerValue("cart.items.max", 20); +var priceMultiplier = client.GetDoubleValue("pricing.multiplier", 1.0); +{{< /code-block >}} +{{% /collapse-content %}} + +{{% collapse-content title="Object flags" level="h4" %}} +{{< code-block lang="csharp" >}} +var config = client.GetObjectValue( + "ui.config", + new Dictionary + { + { "color", "#00A3FF" }, + { "fontSize", 14 }, + } +); +{{< /code-block >}} +{{% /collapse-content %}} + ## Further reading {{< partial name="whats-next/whats-next.html" >}} -[1]: https://github.com/googlesamples/unity-jar-resolver -[2]: https://openupm.com/packages/com.google.external-dependency-manager/ -[3]: https://github.com/DataDog/unity-package -[4]: https://docs.unity3d.com/Manual/gradle-templates.html -[5]: /real_user_monitoring/application_monitoring/unity/setup +[1]: https://openfeature.dev/ +[2]: https://github.com/googlesamples/unity-jar-resolver +[3]: https://openupm.com/packages/com.google.external-dependency-manager/ +[4]: https://github.com/DataDog/unity-package +[5]: https://docs.unity3d.com/Manual/gradle-templates.html +[6]: /real_user_monitoring/application_monitoring/unity/setup From 42525a50de64924a48a87cbe96ce0d8ff1d7bf9b Mon Sep 17 00:00:00 2001 From: typotter Date: Tue, 24 Mar 2026 17:20:55 -0600 Subject: [PATCH 12/18] Remove openfeature URL aliases from Unity docs --- content/en/feature_flags/client/unity.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index ec40f70ee99..2dc9934084a 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -3,8 +3,6 @@ title: Unity Feature Flags description: Set up Datadog Feature Flags for Unity applications. aliases: - /feature_flags/setup/unity/ - - /feature_flags/setup/unity-openfeature/ - - /feature_flags/client/unity-openfeature/ further_reading: - link: "/feature_flags/client/" tag: "Documentation" From f6e2dd7dfa32bd46b1aac743da2f4df5554c2fcb Mon Sep 17 00:00:00 2001 From: typotter Date: Fri, 27 Mar 2026 12:41:53 -0600 Subject: [PATCH 13/18] Update Unity Feature Flags docs for PR #210 API changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - new DatadogFeatureProvider(client) replaces DdFlags.Instance.CreateProvider() - DatadogFeatureProvider is in separate com.datadoghq.unity.flags.openfeature package - using Datadog.Unity.Flags.OpenFeature namespace required - DdFlags.Instance is always non-null (static readonly singleton) - CreateClient() returns IFlagsClient (public interface) - FlagDetails and FlagEvaluationError are public — restore detail methods in direct API section - Installation section updated for two-package architecture and NuGetForUnity --- content/en/feature_flags/client/unity.md | 63 +++++++++++++++++------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 2dc9934084a..4c31975131a 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -24,7 +24,7 @@ This page describes how to instrument your Unity application with the Datadog Fe The Datadog Feature Flags SDK for Unity integrates with [OpenFeature][1], an open standard for feature flag management. This guide explains how to install the SDK, register the Datadog provider, set an evaluation context, and evaluate flags in your application. -
For most applications, the OpenFeature API is the recommended approach. If you need direct access to the underlying FlagsClient—for example, to manage the client lifecycle independently—see Direct FlagsClient integration.
+
For most applications, the OpenFeature API is the recommended approach. If you need direct access to the IFlagsClient—for example, to use native flag value types directly—see Direct FlagsClient integration.
## Getting started @@ -34,6 +34,7 @@ Here's a minimal example to get feature flags working in your Unity app: using System.Collections; using System.Collections.Generic; using Datadog.Unity.Flags; +using Datadog.Unity.Flags.OpenFeature; using OpenFeature; using UnityEngine; @@ -46,7 +47,7 @@ public class FlagsBehavior : MonoBehaviour // 2. Create a client and register the Datadog OpenFeature provider var client = DdFlags.Instance.CreateClient(); - var providerTask = Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); + var providerTask = Api.Instance.SetProviderAsync(new DatadogFeatureProvider(client)); yield return new WaitUntil(() => providerTask.IsCompleted); // 3. Set the evaluation context @@ -74,15 +75,28 @@ The rest of this guide explains each step in detail. ## Installation -Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. +The Datadog Feature Flags SDK ships as two UPM packages: + +- **`com.datadoghq.unity`** — core package, required. Includes `DdFlags`, `IFlagsClient`, and direct flag evaluation. +- **`com.datadoghq.unity.flags.openfeature`** — optional OpenFeature integration. Install this if you want to evaluate flags through the OpenFeature standard API. + +**Install the core package:** 1. Install the [External Dependency Manager for Unity (EDM4U)][2]. This can be done using [Open UPM][3]. 2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][4]. The package URL is `https://github.com/DataDog/unity-package.git`. -3. (Android only) Configure your project to use [Gradle templates][5], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. +**Install the OpenFeature package (optional):** + +3. Install [NuGetForUnity][5] to manage OpenFeature dependencies. + +4. Add the `com.datadoghq.unity.flags.openfeature` package from its Git URL. + +**Android-only steps:** -4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: +5. Configure your project to use [Gradle templates][6], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. + +6. If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: ```groovy constraints { @@ -96,7 +110,7 @@ Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. -For more information about setting up the Unity SDK, see [Unity Monitoring Setup][6]. +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][7]. ## Enable flags @@ -112,16 +126,21 @@ You can also pass configuration options; see [Advanced configuration](#advanced- ## Register the provider -Create a `FlagsClient`, then create and register the Datadog provider with the OpenFeature `Api`. You need to hold a reference to the `FlagsClient` to set the evaluation context later. +Create a `FlagsClient`, then construct a `DatadogFeatureProvider` and register it with the OpenFeature `Api`. Hold a reference to the client — you need it to set the evaluation context. {{< code-block lang="csharp" >}} +using Datadog.Unity.Flags.OpenFeature; using OpenFeature; var client = DdFlags.Instance.CreateClient(); -await Api.Instance.SetProviderAsync(DdFlags.Instance.CreateProvider()); +await Api.Instance.SetProviderAsync(new DatadogFeatureProvider(client)); {{< /code-block >}} -
Call CreateClient() before CreateProvider(). The provider must be bound to an existing client.
+Retrieve the OpenFeature client anywhere in your app to evaluate flags: + +{{< code-block lang="csharp" >}} +var ofClient = Api.Instance.GetClient(); +{{< /code-block >}} ## Set the evaluation context @@ -221,7 +240,7 @@ var fontSize = task.Result.AsStructure["fontSize"].AsInteger; ### Flag evaluation details -When you need evaluation metadata beyond the flag value, use the detail methods. These return both the value and information about why it was chosen: +When you need evaluation metadata beyond the flag value, use the detail methods: {{< code-block lang="csharp" >}} var task = ofClient.GetStringDetailsAsync("paywall.layout", "control"); @@ -266,11 +285,7 @@ DdFlags.Enable(new FlagsConfiguration( ## Direct FlagsClient integration (advanced) -For most applications, the OpenFeature API described above is the recommended approach. Use the `FlagsClient` directly only if you need to manage the evaluation context independently of the OpenFeature provider—for example, to update context without triggering a provider state transition. - -### Create and use a client - -Create and hold a reference to the `FlagsClient`: +For most applications, the OpenFeature API described above is the recommended approach. Use `IFlagsClient` directly if you do not need the OpenFeature abstraction or want to work with Datadog's native flag types. {{% collapse-content title="Create a client" level="h4" %}} {{< code-block lang="csharp" >}} @@ -298,7 +313,7 @@ client.SetEvaluationContext( { if (success) { - Debug.Log("Flags loaded successfully!"); + EvaluateFlags(client); } } ); @@ -337,6 +352,17 @@ var config = client.GetObjectValue( {{< /code-block >}} {{% /collapse-content %}} +{{% collapse-content title="Flag evaluation details" level="h4" %}} +{{< code-block lang="csharp" >}} +var details = client.GetBooleanDetails("checkout.new", false); + +Debug.Log($"Value: {details.Value}"); +Debug.Log($"Variant: {details.Variant ?? "n/a"}"); +Debug.Log($"Reason: {details.Reason ?? "n/a"}"); +Debug.Log($"Error: {details.Error?.ToString() ?? "none"}"); +{{< /code-block >}} +{{% /collapse-content %}} + ## Further reading {{< partial name="whats-next/whats-next.html" >}} @@ -345,5 +371,6 @@ var config = client.GetObjectValue( [2]: https://github.com/googlesamples/unity-jar-resolver [3]: https://openupm.com/packages/com.google.external-dependency-manager/ [4]: https://github.com/DataDog/unity-package -[5]: https://docs.unity3d.com/Manual/gradle-templates.html -[6]: /real_user_monitoring/application_monitoring/unity/setup +[5]: https://github.com/GlitchEnzo/NuGetForUnity +[6]: https://docs.unity3d.com/Manual/gradle-templates.html +[7]: /real_user_monitoring/application_monitoring/unity/setup From 42d96eeec70beb22e85d95264ff65bfb8202a0dd Mon Sep 17 00:00:00 2001 From: typotter Date: Fri, 27 Mar 2026 13:28:17 -0600 Subject: [PATCH 14/18] Fix installation: NuGetForUnity is a transitive UPM dep, not a manual install step --- content/en/feature_flags/client/unity.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 4c31975131a..c4e85784f5c 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -78,7 +78,7 @@ The rest of this guide explains each step in detail. The Datadog Feature Flags SDK ships as two UPM packages: - **`com.datadoghq.unity`** — core package, required. Includes `DdFlags`, `IFlagsClient`, and direct flag evaluation. -- **`com.datadoghq.unity.flags.openfeature`** — optional OpenFeature integration. Install this if you want to evaluate flags through the OpenFeature standard API. +- **`com.datadoghq.unity.flags.openfeature`** — optional OpenFeature integration. Install this if you want to evaluate flags through the OpenFeature standard API. This package declares [NuGetForUnity][5] as a dependency, which is installed automatically and manages the OpenFeature NuGet packages. **Install the core package:** @@ -88,15 +88,13 @@ The Datadog Feature Flags SDK ships as two UPM packages: **Install the OpenFeature package (optional):** -3. Install [NuGetForUnity][5] to manage OpenFeature dependencies. - -4. Add the `com.datadoghq.unity.flags.openfeature` package from its Git URL. +3. Add the `com.datadoghq.unity.flags.openfeature` package from its Git URL. NuGetForUnity is installed automatically as a transitive dependency and restores the OpenFeature packages on first project open. **Android-only steps:** -5. Configure your project to use [Gradle templates][6], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. +4. Configure your project to use [Gradle templates][6], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. -6. If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: +5. If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: ```groovy constraints { From 344f80e97dc452dfe2a91d0e5a383b24b29b2097 Mon Sep 17 00:00:00 2001 From: typotter Date: Tue, 31 Mar 2026 10:09:02 -0600 Subject: [PATCH 15/18] Rewrite Unity Feature Flags docs: direct API only, no OpenFeature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove all OpenFeature references and the openfeature package install steps - Follow iOS page structure: Enable → Create client → Set context → Evaluate → Advanced config - DdFlags.Enable() / DdFlags.Instance.CreateClient() / client.SetEvaluationContext() - Synchronous typed getters: GetBooleanValue, GetStringValue, GetIntegerValue, GetDoubleValue, GetObjectValue - FlagDetails detail methods documented - FlagsConfiguration uses constructor syntax (immutable) - Backup of previous state at typo/unity-feature-flags-docs-openfeature-backup --- content/en/feature_flags/client/unity.md | 297 ++++++----------------- 1 file changed, 80 insertions(+), 217 deletions(-) diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index c4e85784f5c..1d9daefcedc 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -13,88 +13,25 @@ further_reading: - link: "https://github.com/DataDog/dd-sdk-unity" tag: "Source Code" text: "dd-sdk-unity source code" -- link: "https://openfeature.dev/" - tag: "External" - text: "OpenFeature" --- ## Overview This page describes how to instrument your Unity 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 Unity integrates with [OpenFeature][1], an open standard for feature flag management. This guide explains how to install the SDK, register the Datadog provider, set an evaluation context, and evaluate flags in your application. - -
For most applications, the OpenFeature API is the recommended approach. If you need direct access to the IFlagsClient—for example, to use native flag value types directly—see Direct FlagsClient integration.
- -## Getting started - -Here's a minimal example to get feature flags working in your Unity app: - -{{< code-block lang="csharp" >}} -using System.Collections; -using System.Collections.Generic; -using Datadog.Unity.Flags; -using Datadog.Unity.Flags.OpenFeature; -using OpenFeature; -using UnityEngine; - -public class FlagsBehavior : MonoBehaviour -{ - private IEnumerator Start() - { - // 1. Enable the Flags feature after Datadog SDK initialization - DdFlags.Enable(new FlagsConfiguration()); - - // 2. Create a client and register the Datadog OpenFeature provider - var client = DdFlags.Instance.CreateClient(); - var providerTask = Api.Instance.SetProviderAsync(new DatadogFeatureProvider(client)); - yield return new WaitUntil(() => providerTask.IsCompleted); - - // 3. Set the evaluation context - var done = false; - client.SetEvaluationContext( - new FlagsEvaluationContext("user-123", new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" }, - }), - onComplete: _ => done = true - ); - yield return new WaitUntil(() => done); - - // 4. Evaluate flags via the OpenFeature client - var ofClient = Api.Instance.GetClient(); - var flagTask = ofClient.GetBooleanValueAsync("checkout.new", false); - yield return new WaitUntil(() => flagTask.IsCompleted); - Debug.Log($"checkout.new = {flagTask.Result}"); - } -} -{{< /code-block >}} - -The rest of this guide explains each step in detail. +This guide explains how to install and enable the SDK, create and use a `FlagsClient`, and configure advanced options. ## Installation -The Datadog Feature Flags SDK ships as two UPM packages: - -- **`com.datadoghq.unity`** — core package, required. Includes `DdFlags`, `IFlagsClient`, and direct flag evaluation. -- **`com.datadoghq.unity.flags.openfeature`** — optional OpenFeature integration. Install this if you want to evaluate flags through the OpenFeature standard API. This package declares [NuGetForUnity][5] as a dependency, which is installed automatically and manages the OpenFeature NuGet packages. +Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity SDK includes feature flags support. -**Install the core package:** +1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. -1. Install the [External Dependency Manager for Unity (EDM4U)][2]. This can be done using [Open UPM][3]. +2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. -2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][4]. The package URL is `https://github.com/DataDog/unity-package.git`. +3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. -**Install the OpenFeature package (optional):** - -3. Add the `com.datadoghq.unity.flags.openfeature` package from its Git URL. NuGetForUnity is installed automatically as a transitive dependency and restores the OpenFeature packages on first project open. - -**Android-only steps:** - -4. Configure your project to use [Gradle templates][6], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. - -5. If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: +4. (Android only) If you build and receive `Duplicate class` errors (common in Unity 2022.x), add the following code to the `dependencies` block of your `mainTemplate.gradle`: ```groovy constraints { @@ -108,54 +45,59 @@ The Datadog Feature Flags SDK ships as two UPM packages: Initialize Datadog as early as possible in your app lifecycle. Navigate to your `Project Settings` and click on the `Datadog` section to configure your client token, environment, and other settings. -For more information about setting up the Unity SDK, see [Unity Monitoring Setup][7]. +For more information about setting up the Unity SDK, see [Unity Monitoring Setup][5]. ## Enable flags -After initializing Datadog, enable flags in your application code: +After initializing Datadog, enable `Flags` to attach it to the current Datadog SDK instance and prepare for client creation and flag evaluation: {{< code-block lang="csharp" >}} using Datadog.Unity.Flags; -DdFlags.Enable(new FlagsConfiguration()); +DdFlags.Enable(); {{< /code-block >}} -You can also pass configuration options; see [Advanced configuration](#advanced-configuration). +You can also pass a configuration object; see [Advanced configuration](#advanced-configuration). -## Register the provider +## Create and retrieve a client -Create a `FlagsClient`, then construct a `DatadogFeatureProvider` and register it with the OpenFeature `Api`. Hold a reference to the client — you need it to set the evaluation context. +Create a client once, typically during app startup: {{< code-block lang="csharp" >}} -using Datadog.Unity.Flags.OpenFeature; -using OpenFeature; - var client = DdFlags.Instance.CreateClient(); -await Api.Instance.SetProviderAsync(new DatadogFeatureProvider(client)); {{< /code-block >}} -Retrieve the OpenFeature client anywhere in your app to evaluate flags: +You can also create multiple clients by providing the `name` parameter: {{< code-block lang="csharp" >}} -var ofClient = Api.Instance.GetClient(); +var checkoutClient = DdFlags.Instance.CreateClient("checkout"); {{< /code-block >}} +
If a client with the given name already exists, the existing instance is reused.
+ ## Set the evaluation context -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. 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. +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. {{< code-block lang="csharp" >}} client.SetEvaluationContext( - new FlagsEvaluationContext("user-123", new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" }, - }), + new FlagsEvaluationContext( + targetingKey: "user-123", + attributes: new Dictionary + { + { "email", "user@example.com" }, + { "tier", "premium" }, + } + ), onComplete: success => { if (success) { - Debug.Log("Flags loaded successfully!"); + // Flags are ready — begin evaluating + } + else + { + // Fetch failed — evaluations return default values } } ); @@ -165,27 +107,18 @@ This method fetches flag assignments from the server asynchronously in the backg ## 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. +After creating the `FlagsClient` and setting its evaluation context, you can start reading 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). The OpenFeature client provides typed async methods for each value type. Because Unity's `MonoBehaviour` does not support `await`, use coroutines to bridge async flag evaluation: - -{{< code-block lang="csharp" >}} -private IEnumerator EvaluateFlags() -{ - var ofClient = Api.Instance.GetClient(); - var task = ofClient.GetBooleanValueAsync("checkout.new", false); - yield return new WaitUntil(() => task.IsCompleted); - Debug.Log($"checkout.new = {task.Result}"); -} -{{< /code-block >}} +Each flag is identified by a _key_ (a unique string) and can be evaluated with a _typed getter_ 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. ### Boolean flags +Use `GetBooleanValue(key, defaultValue)` for flags that represent on/off or true/false conditions. For example: + {{< code-block lang="csharp" >}} -var task = ofClient.GetBooleanValueAsync("checkout.new", false); -yield return new WaitUntil(() => task.IsCompleted); +var isNewCheckoutEnabled = client.GetBooleanValue("checkout.new", false); -if (task.Result) +if (isNewCheckoutEnabled) { ShowNewCheckoutFlow(); } @@ -197,11 +130,12 @@ else ### String flags +Use `GetStringValue(key, defaultValue)` for flags that select between multiple variants or configuration strings. For example: + {{< code-block lang="csharp" >}} -var task = ofClient.GetStringValueAsync("ui.theme", "light"); -yield return new WaitUntil(() => task.IsCompleted); +var theme = client.GetStringValue("ui.theme", "light"); -switch (task.Result) +switch (theme) { case "light": SetLightTheme(); break; case "dark": SetDarkTheme(); break; @@ -211,46 +145,57 @@ switch (task.Result) ### Integer and double flags +For numeric flags, use `GetIntegerValue(key, defaultValue)` or `GetDoubleValue(key, defaultValue)`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier: + {{< code-block lang="csharp" >}} -var maxItemsTask = ofClient.GetIntegerValueAsync("cart.items.max", 20); -var multiplierTask = ofClient.GetDoubleValueAsync("pricing.multiplier", 1.0); -yield return new WaitUntil(() => maxItemsTask.IsCompleted && multiplierTask.IsCompleted); +var maxItems = client.GetIntegerValue("cart.items.max", 20); -var maxItems = maxItemsTask.Result; -var priceMultiplier = multiplierTask.Result; +var priceMultiplier = client.GetDoubleValue("pricing.multiplier", 1.0); {{< /code-block >}} ### Object flags -{{< code-block lang="csharp" >}} -var defaultConfig = new Value(new Structure(new Dictionary -{ - { "color", new Value("#00A3FF") }, - { "fontSize", new Value(14) }, -})); +For structured or JSON-like data, use `GetObjectValue(key, defaultValue)`. This method returns an `object`, which can be cast to the appropriate type. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together. For example: -var task = ofClient.GetObjectValueAsync("ui.config", defaultConfig); -yield return new WaitUntil(() => task.IsCompleted); +{{< code-block lang="csharp" >}} +var config = client.GetObjectValue( + "ui.config", + new Dictionary + { + { "color", "#00A3FF" }, + { "fontSize", 14 }, + } +); -var color = task.Result.AsStructure["color"].AsString; -var fontSize = task.Result.AsStructure["fontSize"].AsInteger; +if (config is Dictionary configDict) +{ + var color = configDict["color"] as string; + var fontSize = (int)configDict["fontSize"]; +} {{< /code-block >}} ### Flag evaluation details -When you need evaluation metadata beyond the flag value, use the detail methods: +When you need more than just the flag value, use the `GetDetails` methods. These methods return both the evaluated value and metadata explaining the evaluation: + +* `GetBooleanDetails(key, defaultValue)` -> `FlagDetails` +* `GetStringDetails(key, defaultValue)` -> `FlagDetails` +* `GetIntegerDetails(key, defaultValue)` -> `FlagDetails` +* `GetDoubleDetails(key, defaultValue)` -> `FlagDetails` + +For example: {{< code-block lang="csharp" >}} -var task = ofClient.GetStringDetailsAsync("paywall.layout", "control"); -yield return new WaitUntil(() => task.IsCompleted); -var details = task.Result; - -Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") -Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable -Debug.Log($"Reason: {details.Reason}"); // Why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") -Debug.Log($"ErrorType: {details.ErrorType}"); // Error code, if any +var details = client.GetStringDetails("paywall.layout", "control"); + +Debug.Log($"Value: {details.Value}"); // Evaluated value (for example: "A", "B", or "control") +Debug.Log($"Variant: {details.Variant}"); // Variant name, if applicable +Debug.Log($"Reason: {details.Reason}"); // Why this value was chosen (for example: "TARGETING_MATCH" or "DEFAULT") +Debug.Log($"Error: {details.Error?.ToString()}"); // The error that occurred during evaluation, if any {{< /code-block >}} +Flag details may help you debug evaluation behavior and understand why a user received a given value. + ## Advanced configuration The `DdFlags.Enable()` API accepts optional configuration with options listed below. @@ -281,94 +226,12 @@ DdFlags.Enable(new FlagsConfiguration( `customEvaluationEndpoint` : Configures a custom server URL for sending flags evaluation telemetry. -## Direct FlagsClient integration (advanced) - -For most applications, the OpenFeature API described above is the recommended approach. Use `IFlagsClient` directly if you do not need the OpenFeature abstraction or want to work with Datadog's native flag types. - -{{% collapse-content title="Create a client" level="h4" %}} -{{< code-block lang="csharp" >}} -var client = DdFlags.Instance.CreateClient(); -{{< /code-block >}} - -You can also create named clients: - -{{< code-block lang="csharp" >}} -var checkoutClient = DdFlags.Instance.CreateClient("checkout"); -{{< /code-block >}} - -
If a client with the given name already exists, the existing instance is reused.
-{{% /collapse-content %}} - -{{% collapse-content title="Set the evaluation context" level="h4" %}} -{{< code-block lang="csharp" >}} -client.SetEvaluationContext( - new FlagsEvaluationContext("user-123", new Dictionary - { - { "email", "user@example.com" }, - { "tier", "premium" }, - }), - onComplete: success => - { - if (success) - { - EvaluateFlags(client); - } - } -); -{{< /code-block >}} -{{% /collapse-content %}} - -{{% collapse-content title="Boolean flags" level="h4" %}} -{{< code-block lang="csharp" >}} -var isEnabled = client.GetBooleanValue("checkout.new", false); -{{< /code-block >}} -{{% /collapse-content %}} - -{{% collapse-content title="String flags" level="h4" %}} -{{< code-block lang="csharp" >}} -var theme = client.GetStringValue("ui.theme", "light"); -{{< /code-block >}} -{{% /collapse-content %}} - -{{% collapse-content title="Integer and double flags" level="h4" %}} -{{< code-block lang="csharp" >}} -var maxItems = client.GetIntegerValue("cart.items.max", 20); -var priceMultiplier = client.GetDoubleValue("pricing.multiplier", 1.0); -{{< /code-block >}} -{{% /collapse-content %}} - -{{% collapse-content title="Object flags" level="h4" %}} -{{< code-block lang="csharp" >}} -var config = client.GetObjectValue( - "ui.config", - new Dictionary - { - { "color", "#00A3FF" }, - { "fontSize", 14 }, - } -); -{{< /code-block >}} -{{% /collapse-content %}} - -{{% collapse-content title="Flag evaluation details" level="h4" %}} -{{< code-block lang="csharp" >}} -var details = client.GetBooleanDetails("checkout.new", false); - -Debug.Log($"Value: {details.Value}"); -Debug.Log($"Variant: {details.Variant ?? "n/a"}"); -Debug.Log($"Reason: {details.Reason ?? "n/a"}"); -Debug.Log($"Error: {details.Error?.ToString() ?? "none"}"); -{{< /code-block >}} -{{% /collapse-content %}} - ## Further reading {{< partial name="whats-next/whats-next.html" >}} -[1]: https://openfeature.dev/ -[2]: https://github.com/googlesamples/unity-jar-resolver -[3]: https://openupm.com/packages/com.google.external-dependency-manager/ -[4]: https://github.com/DataDog/unity-package -[5]: https://github.com/GlitchEnzo/NuGetForUnity -[6]: https://docs.unity3d.com/Manual/gradle-templates.html -[7]: /real_user_monitoring/application_monitoring/unity/setup +[1]: https://github.com/googlesamples/unity-jar-resolver +[2]: https://openupm.com/packages/com.google.external-dependency-manager/ +[3]: https://github.com/DataDog/unity-package +[4]: https://docs.unity3d.com/Manual/gradle-templates.html +[5]: /real_user_monitoring/application_monitoring/unity/setup From 5854a2197c0ec061adbe557e7a00e7967e6dd3a4 Mon Sep 17 00:00:00 2001 From: Joe Peeples Date: Fri, 3 Apr 2026 16:52:22 -0400 Subject: [PATCH 16/18] add new Unity page to side nav --- config/_default/menus/main.en.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/_default/menus/main.en.yaml b/config/_default/menus/main.en.yaml index 05d75fb4375..bcd9021b8fd 100644 --- a/config/_default/menus/main.en.yaml +++ b/config/_default/menus/main.en.yaml @@ -5855,6 +5855,11 @@ menu: parent: feature_flags_client identifier: feature_flags_client_react_native weight: 106 + - name: Unity + url: feature_flags/client/unity + parent: feature_flags_client + identifier: feature_flags_client_unity + weight: 107 - name: Server SDKs url: feature_flags/server parent: feature_flags From ded1f83b59ddd302ab0ba5da20d79018134657cc Mon Sep 17 00:00:00 2001 From: typotter Date: Tue, 7 Apr 2026 13:40:04 -0600 Subject: [PATCH 17/18] Address joepeeples review comments on unity.md - Remove /feature_flags/setup/unity/ alias (URL never existed) - Simplify Git URL installation step wording - ensure -> help ensure (Vale rule) - once the -> after the (Vale rule) --- content/en/feature_flags/client/unity.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/content/en/feature_flags/client/unity.md b/content/en/feature_flags/client/unity.md index 1d9daefcedc..7d8a50613c5 100644 --- a/content/en/feature_flags/client/unity.md +++ b/content/en/feature_flags/client/unity.md @@ -1,8 +1,6 @@ --- title: Unity Feature Flags description: Set up Datadog Feature Flags for Unity applications. -aliases: - - /feature_flags/setup/unity/ further_reading: - link: "/feature_flags/client/" tag: "Documentation" @@ -27,7 +25,7 @@ Declare the Datadog Unity SDK as a dependency in your project. The Datadog Unity 1. Install the [External Dependency Manager for Unity (EDM4U)][1]. This can be done using [Open UPM][2]. -2. Add the Datadog SDK Unity package from its Git URL at [https://github.com/DataDog/unity-package][3]. The package URL is `https://github.com/DataDog/unity-package.git`. +2. Add the [Datadog SDK Unity package][3] using its Git URL `https://github.com/DataDog/unity-package.git`. 3. (Android only) Configure your project to use [Gradle templates][4], and enable both `Custom Main Template` and `Custom Gradle Properties Template`. @@ -77,7 +75,7 @@ var checkoutClient = DdFlags.Instance.CreateClient("checkout"); ## Set the evaluation context -Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to ensure proper targeting. +Define who or what the flag evaluation applies to using a `FlagsEvaluationContext`. The evaluation context includes user or session information used to determine which flag variations should be returned. Call this method before evaluating flags to help ensure proper targeting. {{< code-block lang="csharp" >}} client.SetEvaluationContext( @@ -103,7 +101,7 @@ client.SetEvaluationContext( ); {{< /code-block >}} -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 once the background operation completes. +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. ## Evaluate flags From 0acbbb03d65e91f8795ee4da0b6023ef3f30d062 Mon Sep 17 00:00:00 2001 From: typotter Date: Tue, 14 Apr 2026 10:36:13 -0600 Subject: [PATCH 18/18] Add evaluation metrics section to Java feature flags docs Documents the feature_flag.evaluations OTel counter metric added in dd-openfeature v1.61.0. Covers optional OTel SDK dependencies, OTLP endpoint configuration, and metric attribute reference. Also bumps dd-openfeature version references from 1.57.0 to 1.61.0. --- content/en/feature_flags/server/java.md | 95 +++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/content/en/feature_flags/server/java.md b/content/en/feature_flags/server/java.md index e0e2ab5539e..481547cf689 100644 --- a/content/en/feature_flags/server/java.md +++ b/content/en/feature_flags/server/java.md @@ -24,7 +24,7 @@ The Java SDK integrates feature flags directly into the Datadog APM tracer and i The Datadog Feature Flags SDK for Java requires: - **Java 11 or higher** -- **Datadog Java APM Tracer**: Version **1.57.0** or later +- **Datadog Java APM Tracer**: Version **1.61.0** or later - **OpenFeature SDK**: Version **1.18.2** or later - **Datadog Agent**: Version **7.x or later** with [Remote Configuration][1] enabled - **Datadog API Key**: Required for Remote Configuration @@ -49,7 +49,7 @@ dependencies { implementation 'dev.openfeature:sdk:1.18.2' // Datadog OpenFeature Provider - implementation 'com.datadoghq:dd-openfeature:1.57.0' + implementation 'com.datadoghq:dd-openfeature:1.61.0' } {{< /code-block >}} {{% /tab %}} @@ -63,7 +63,7 @@ dependencies { implementation("dev.openfeature:sdk:1.18.2") // Datadog OpenFeature Provider - implementation("com.datadoghq:dd-openfeature:1.57.0") + implementation("com.datadoghq:dd-openfeature:1.61.0") } {{< /code-block >}} {{% /tab %}} @@ -84,7 +84,7 @@ Add the following dependencies to your `pom.xml`: com.datadoghq dd-openfeature - 1.57.0 + 1.61.0 {{< /code-block >}} @@ -207,7 +207,7 @@ public class App { } {{< /code-block >}} -Use `setProviderAndWait()` to block evaluation until the initial flag configuration is received from Remote Configuration. This ensures flags are ready before the application starts serving traffic. The default timeout is 30 seconds. +Use `setProviderAndWait()` to block evaluation until the initial flag configuration is received from Remote Configuration. This helps ensure flags are ready before the application starts serving traffic. The default timeout is 30 seconds. `ProviderNotReadyError` is an OpenFeature SDK exception thrown when the provider times out during initialization. Catching it allows the application to start with default flag values if Remote Configuration is unavailable. If not caught, the exception propagates and may prevent application startup. Handle this based on your availability requirements. @@ -323,6 +323,89 @@ if (config.isStructure()) { {{% /tab %}} {{< /tabs >}} +## Evaluation metrics + +The Datadog OpenFeature Provider records a `feature_flag.evaluations` OTel counter metric on every flag evaluation. Use this metric to track how often flags are evaluated, which variants are served, and evaluation reasons across your application. + +Evaluation metrics are available from `dd-openfeature` version 1.61.0. + +### Add the required dependencies + +Evaluation metrics require the OpenTelemetry SDK on the application classpath. These dependencies are optional — the provider operates without them, but no evaluation metrics are emitted. + +{{< tabs >}} +{{% tab "Gradle (Groovy)" %}} +Add the following dependencies to your `build.gradle`: + +{{< code-block lang="groovy" filename="build.gradle" >}} +dependencies { + implementation 'io.opentelemetry:opentelemetry-sdk-metrics:1.47.0' + implementation 'io.opentelemetry:opentelemetry-exporter-otlp:1.47.0' +} +{{< /code-block >}} +{{% /tab %}} + +{{% tab "Gradle (Kotlin)" %}} +Add the following dependencies to your `build.gradle.kts`: + +{{< code-block lang="kotlin" filename="build.gradle.kts" >}} +dependencies { + implementation("io.opentelemetry:opentelemetry-sdk-metrics:1.47.0") + implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.47.0") +} +{{< /code-block >}} +{{% /tab %}} + +{{% tab "Maven" %}} +Add the following dependencies to your `pom.xml`: + +{{< code-block lang="xml" filename="pom.xml" >}} + + + io.opentelemetry + opentelemetry-sdk-metrics + 1.47.0 + + + io.opentelemetry + opentelemetry-exporter-otlp + 1.47.0 + + +{{< /code-block >}} +{{% /tab %}} +{{< /tabs >}} + +Any OpenTelemetry API 1.x version is compatible. The `opentelemetry-api` artifact is included as a transitive dependency of `dd-openfeature`. + +### Configure the OTLP endpoint + +Metrics are exported to the Datadog Agent's OTLP receiver through OTLP HTTP/protobuf. The endpoint is resolved in the following order: + +| Priority | Environment variable | Behavior | +|---|---|---| +| 1 | `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | Used as-is (must include the full path, for example, `http://agent:4318/v1/metrics`) | +| 2 | `OTEL_EXPORTER_OTLP_ENDPOINT` | Base URL; `/v1/metrics` is appended automatically | +| 3 | (none set) | Defaults to `http://localhost:4318/v1/metrics` | + +The Datadog Agent must have its OTLP receiver enabled on port 4318. + +### Metric reference + +**Metric name:** `feature_flag.evaluations` +**Type:** Monotonic counter (cumulative temporality) +**Export interval:** Every 10 seconds + +| Attribute | When present | Description | Example | +|---|---|---|---| +| `feature_flag.key` | Always | Flag key | `my-feature` | +| `feature_flag.result.variant` | Always | Resolved variant key (empty string if null) | `on`, `variant-a` | +| `feature_flag.result.reason` | Always | Evaluation reason (lowercased) | `targeting_match`, `static`, `split`, `error`, `disabled`, `default` | +| `error.type` | On error only | Error code (lowercased) | `flag_not_found`, `type_mismatch`, `provider_not_ready` | +| `feature_flag.result.allocation_key` | When allocation matched | Allocation key from flag config | `default-allocation` | + +If the OTel SDK dependencies are absent from the classpath, the provider logs a warning at startup and continues without emitting metrics. Flag evaluation is not affected. + ## Error handling The OpenFeature SDK uses a default value pattern. If evaluation fails for any reason, the default value you provide is returned. @@ -422,7 +505,7 @@ The `Provider` instance is shared globally. Client names are for organizational ## Best practices ### Initialize early -Initialize the OpenFeature provider as early as possible in your application lifecycle (for example, in `main()` or application startup). This ensures flags are ready before business logic executes. +Initialize the OpenFeature provider as early as possible in your application lifecycle (for example, in `main()` or application startup). This helps ensure flags are ready before business logic executes. ### Use meaningful default values Always provide sensible default values that maintain safe behavior if flag evaluation fails: