Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions hugo/content/en/feature_flags/client/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
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. Loading a subset reduces the size of the flag configuration that 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. 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>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<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>
<div class="alert alert-warning">Team tags can change when flag ownership changes, which changes the flags your application loads. Instead of selecting by team tags, add tags to your flags specifically for selection, such as <code>app:checkout-web</code>.</div>


#### 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).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 (invalid_tag). The SDK then drops the whole selection and requests the full flag configuration.

Suggested sentence after this list:

A selection cannot include a tag longer than 200 bytes, so keep the tags you add to flags for selection at 200 bytes or less.

- 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:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 (too_many_values). Another example is tags that fail to load (tag_load_failed). In my test, a selection with 31 tags and 31 key patterns of 200 bytes each passed the SDK checks. Datadog then ignored it with too_many_values, and the SDK logged "flagSelection was ignored by the server (too_many_values)".

Suggested text for this paragraph:

Because the SDK checks these limits first, selections that fail them never reach Datadog. Datadog can still ignore a selection that passes these checks, for example when the selection is too long to send in one request. In that case, Datadog returns the full flag configuration with a DD-Flag-Selection-Ignored header that gives one of the following reasons, and the SDK logs an error to the browser console:


| 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. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Comment from Claude working with Aaron Silverman (aarsilv):

[P3] Consider <DETAIL> instead of <LIMIT> in this message. For malformed_selection, the text in that position is not a limit: "flagSelection must be an object with optional tags and keyPatterns string arrays". <DETAIL> fits every case.

| `Datadog Browser SDK: flagSelection was ignored by the server (<REASON>). Loaded the full flag configuration.` | Datadog ignored the selection. See the reasons above. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `Datadog Browser SDK: flagSelection was ignored by the server (<REASON>). Loaded the full flag configuration.` | Datadog ignored the selection. See the reasons above. |
| `Datadog Browser SDK: flagSelection was ignored by the server (<REASON>). Loaded the full flag configuration.` | Datadog ignored the selection. See the reasons in the previous table. |


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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`flagSelection` does not filter configuration you supply with [`initialFlagsConfiguration`](#supply-initial-precomputed-fallback-data); the SDK uses it as provided.
`flagSelection` does not filter configuration that you supply with `initialFlagsConfiguration`. The SDK uses that configuration as provided. For details, see the [Supply initial precomputed fallback data](#supply-initial-precomputed-fallback-data) section.


#### 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].

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 fetch:

  • The proxy must keep the selected_flag_tags and selected_flag_key_patterns query parameters, including repeated ones.
  • A cache in front of the rules fetch must include these parameters in its cache key. If it does not, two selections can share one cached response.

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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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/
3 changes: 3 additions & 0 deletions hugo/content/en/feature_flags/guide/proxy_sdk_traffic.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 DatadogProvider. This new paragraph and the new link from the browser SDK page send readers to these examples.

Line 177 says "Pass configuration options to DatadogBrowserFlagging.init()." All three code samples in this tab call DatadogBrowserFlagging.init(), and the first one imports it from @datadog/browser-flagging. That package is not on npm: npm view @datadog/browser-flagging returns 404. The published SDK is @datadog/openfeature-browser, which exports DatadogProvider. The option names in the samples are correct: flaggingProxy, customHeaders, and proxy are all DatadogProvider options. The samples also omit applicationId and env, which the browser SDK page lists as required for live configuration.

Suggested text for line 177: "Pass these options to DatadogProvider from @datadog/openfeature-browser."

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 (customHeaders or proxy).

This problem is older than this PR. proxy_server_setup.md uses DatadogBrowserFlagging too and can get the same fix later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
If you use [`flagSelection`][3] to load a subset of flags, your proxy must return the `DD-Flag-Selection-Ignored` response header to the browser unchanged. Datadog sets this header when it ignores a selection and returns the full flag configuration. If your proxy is on a different origin from your application, also list the header in the `Access-Control-Expose-Headers` response header. If the browser cannot read the header, the full configuration still loads, but the SDK cannot report that the selection was ignored.


### 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.
Expand Down Expand Up @@ -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 %}}

Expand Down
Loading