Repository navigation
[FFL-3457] Document flag selection for the browser SDK #41060
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
676bb1c
0c7eb45
940ea21
df13ffd
94fea48
c886cb7
c359413
cea564f
ae4d378
162be28
56fda8b
2b8c706
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -85,6 +85,90 @@ const provider = new DatadogProvider({ | |||||
| }); | ||||||
| ``` | ||||||
|
|
||||||
| ### Load a subset of flags | ||||||
|
|
||||||
| In `@datadog/openfeature-browser` 2.2.0 and later, use `flagSelection` to load only the flags your application needs instead of every flag in the environment. Selecting a subset reduces the size of the flag configuration the SDK downloads and caches, which helps when an environment contains flags for many applications. Pass `flagSelection` to the provider when you create it; the selection is fixed for the provider's lifetime, so to load a different set of flags, create a new provider. | ||||||
|
|
||||||
| `flagSelection` accepts two optional lists: | ||||||
|
|
||||||
| `tags` | ||||||
| : Flag tags to match, such as `app:checkout-web`. A flag matches if it has any of the listed tags. Tags match exactly and are case-sensitive. | ||||||
|
|
||||||
| `keyPatterns` | ||||||
| : Patterns to match against the whole flag key. `*` matches any sequence of characters, including none, anywhere in the pattern. Every other character, including `?`, `[`, `]`, `{`, and `}`, matches only itself. For example, `checkout-*` matches `checkout-banner` but not `new-checkout-banner`, and `*-checkout-*` matches `new-checkout-banner`. | ||||||
|
|
||||||
| A flag loads if it matches any listed tag **or** any key pattern. In the following example, the SDK loads every flag tagged `app:checkout-web` and every flag whose key starts with `checkout-`: | ||||||
|
|
||||||
| ```javascript | ||||||
| import { DatadogProvider } from '@datadog/openfeature-browser'; | ||||||
|
|
||||||
| const provider = new DatadogProvider({ | ||||||
| applicationId: '<APPLICATION_ID>', | ||||||
| clientToken: '<CLIENT_TOKEN>', | ||||||
| site: '{{< region-param key="dd_site" code="true" >}}', | ||||||
| env: '<ENV_NAME>', | ||||||
| flagSelection: { | ||||||
| tags: ['app:checkout-web'], | ||||||
| keyPatterns: ['checkout-*'], | ||||||
| }, | ||||||
| }); | ||||||
| ``` | ||||||
|
|
||||||
| <div class="alert alert-warning">Team tags can change when ownership changes, which could change the flags your application loads. Add tags to your flags specifically for selection, such as <code>app:checkout-web</code>, rather than selecting by team tags.</div> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| #### Limits and validation | ||||||
|
|
||||||
| Before sending the selection, the SDK trims leading and trailing whitespace from each value, removes empty values and duplicates, and sorts each list. After this processing, the selection must meet these limits: | ||||||
|
|
||||||
| - `tags` contains at most 31 values. | ||||||
| - `keyPatterns` contains at most 31 values. | ||||||
| - Each tag is at most 200 bytes (UTF-8). | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Comment from Claude working with Aaron Silverman (aarsilv): [P3] Consider one sentence that connects this limit to the tags on flags. Datadog lets you add a tag longer than 200 bytes to a flag, and a reader can then try to select it. A selection with that tag fails the SDK check ( Suggested sentence after this list:
|
||||||
| - Each key pattern is at most 200 bytes (UTF-8). | ||||||
|
|
||||||
| If both lists are empty after this processing, the SDK sends no selection and loads the full flag configuration without logging an error. | ||||||
|
|
||||||
| If the flag selection is malformed or exceeds a limit, the SDK does not send it in the flag configuration request, logs an error to the browser console, and loads the full flag configuration. | ||||||
|
|
||||||
| Datadog can also ignore a selection and return the full flag configuration. In that case, the response includes a `DD-Flag-Selection-Ignored` header with one of the following reasons, and the SDK logs an error to the browser console: | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Comment from Claude working with Aaron Silverman (aarsilv): [P2] Please connect this paragraph to line 130. Line 130 says that the SDK does not send a selection that fails these limits. This paragraph then lists the same limits as reasons for Datadog to ignore a selection. So a reader can expect this header for a selection that the SDK did not send. With the SDK, this header reports problems that the SDK does not check. One example is a selection that is too long to send in one request ( Suggested text for this paragraph:
|
||||||
|
|
||||||
| | Reason | Meaning | | ||||||
| | --- | --- | | ||||||
| | `too_many_values` | A list contains more than 31 values, or the selection is too long to send in one request. | | ||||||
| | `invalid_tag` | A tag is longer than 200 bytes. | | ||||||
| | `invalid_key_pattern` | A key pattern is longer than 200 bytes. | | ||||||
| | `malformed_selection` | The selection could not be parsed. | | ||||||
| | `tag_load_failed` | Flag tags could not be loaded for this request. The full configuration is returned so that evaluation can continue. | | ||||||
|
|
||||||
| The SDK logs these errors to the browser console: | ||||||
|
|
||||||
| | Message | Cause | | ||||||
| | --- | --- | | ||||||
| | `Datadog Browser SDK: flagSelection was not sent (<REASON>: <LIMIT>). Loading the full flag configuration.` | The selection is malformed or exceeds a limit. | | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Comment from Claude working with Aaron Silverman (aarsilv): [P3] Consider |
||||||
| | `Datadog Browser SDK: flagSelection was ignored by the server (<REASON>). Loaded the full flag configuration.` | Datadog ignored the selection. See the reasons above. | | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| If you route flag configuration requests through a proxy, see [Proxy Feature Flag SDK Traffic][7] for the header your proxy must pass through. | ||||||
|
|
||||||
| #### Evaluate flags outside the selection | ||||||
|
|
||||||
| Flags outside the selection are not loaded. Evaluating one of these flags returns the default value you supply, with the error code `FLAG_NOT_FOUND`: | ||||||
|
|
||||||
| {{< code-block lang="javascript" >}} | ||||||
| const client = OpenFeature.getClient(); | ||||||
| // 'search-ranking' has no app:checkout-web tag and does not match checkout-* | ||||||
| const details = client.getBooleanDetails('search-ranking', false); | ||||||
|
|
||||||
| console.log(details.value); // false (the supplied default) | ||||||
| console.log(details.errorCode); // 'FLAG_NOT_FOUND' | ||||||
| {{< /code-block >}} | ||||||
|
|
||||||
| #### Initial configuration is not filtered | ||||||
|
|
||||||
| `flagSelection` does not filter configuration you supply with [`initialFlagsConfiguration`](#supply-initial-precomputed-fallback-data); the SDK uses it as provided. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| #### Rules-based configuration | ||||||
|
|
||||||
| `fetchRulesConfiguration()` from `@datadog/openfeature-browser/rules-based` accepts the same `flagSelection` option, with the same matching rules and limits. The request URL, including the encoded selection, must be at most 8,192 bytes. If it would be longer, the SDK does not send the selection, logs a `too_many_values` error to the browser console, and loads the full configuration. See [Browser Rules-Based Evaluation][4]. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Comment from Claude working with Aaron Silverman (aarsilv): Heads up: cc @sameerank. Rules-based fetches send the selection in the URL query string. The precompute request sends it in the POST body instead. This matters when an application routes the rules fetch through its own proxy or a custom
No change requested in this PR. The React Native rules fetch helper in DataDog/dd-sdk-reactnative#1508 requests the same endpoint, so the same points apply there if it adds selection support. |
||||||
|
|
||||||
| ## Set the evaluation context | ||||||
|
|
||||||
| Define who or what the flag evaluation applies to using an evaluation context. The evaluation context includes user or session information used to determine which flag variations should be returned. Reference these attributes in your targeting rules to control who sees each variant. | ||||||
|
|
@@ -245,6 +329,7 @@ The web provider also supports these optional settings: | |||||
| | `customHeaders` | unset | Add headers to flag-fetch requests. | | ||||||
| | `overwriteRequestHeaders` | `false` | Replace default request headers with `customHeaders`. | | ||||||
| | `flagConfigurationFetch` | `globalThis.fetch` | Provide a Fetch-compatible implementation for flag configuration requests. | | ||||||
| | `flagSelection` | unset | Load only the flags that match a set of tags or key patterns. See [Load a subset of flags](#load-a-subset-of-flags). | | ||||||
|
|
||||||
| ### Supply initial precomputed fallback data | ||||||
|
|
||||||
|
|
@@ -368,3 +453,4 @@ The Web SDK flag shape requires `variants`, `defaultVariant`, and `disabled`. Om | |||||
| [4]: /feature_flags/implementation_patterns/browser_rules_based_evaluation/ | ||||||
| [5]: /feature_flags/concepts/monthly_flag_configuration_requests/ | ||||||
| [6]: /feature_flags/implementation_patterns/browser_rules_based_evaluation/#getting-started | ||||||
| [7]: /feature_flags/guide/proxy_sdk_traffic/ | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -203,6 +203,8 @@ DatadogBrowserFlagging.init({ | |||||
| }); | ||||||
| {{< /code-block >}} | ||||||
|
|
||||||
| If you use [`flagSelection`][3] to load a subset of flags, return the `DD-Flag-Selection-Ignored` response header to the browser unchanged. If your proxy is on a different origin from your application, also list the header in the `Access-Control-Expose-Headers` response header. Datadog sets this header when it ignores a selection and returns the full flag configuration. If the browser cannot read the header, the full configuration still loads, but the SDK cannot report that the selection was ignored. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Comment from Claude working with Aaron Silverman (aarsilv): [P1] Please change this tab's examples to Line 177 says "Pass configuration options to Suggested text for line 177: "Pass these options to Suggested first sample: import { DatadogProvider } from '@datadog/openfeature-browser';
const provider = new DatadogProvider({
applicationId: '<APPLICATION_ID>',
clientToken: '<CLIENT_TOKEN>',
site: 'datadoghq.com',
env: '<ENV_NAME>',
flaggingProxy: 'https://proxy.example.com/precompute-assignments',
});The other two samples use the same constructor with the same four required options, and keep their extra option ( This problem is older than this PR.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| ### Event upload proxy | ||||||
|
|
||||||
| Browser flag event data (exposures and evaluations) is sent through the standard Browser SDK intake pipeline. To route this traffic through a proxy, set the `proxy` option to a URL on your domain. | ||||||
|
|
@@ -234,6 +236,7 @@ The `proxy` option also accepts a function that receives the decoded `path` and | |||||
|
|
||||||
| [1]: /getting_started/site/ | ||||||
| [2]: /real_user_monitoring/guide/proxy-rum-data/ | ||||||
| [3]: /feature_flags/client/javascript/#load-a-subset-of-flags | ||||||
|
|
||||||
| {{% /tab %}} | ||||||
|
|
||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.