Skip to content

[FFL-3457] Document flag selection for the browser SDK - #41060

Open
mark-caii wants to merge 12 commits into
masterfrom
mark.cai/FFL-3457
Open

mark-caii wants to merge 12 commits into
masterfrom
mark.cai/FFL-3457

Conversation

@mark-caii

@mark-caii mark-caii commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do? What is the motivation?

Ticket: FFL-3457

Documents the flagSelection option of the browser SDK (@datadog/openfeature-browser), which loads only the flags that match a set of tags or key patterns.

  • feature_flags/client/javascript.md: adds flagSelection to the provider options table and a Load a subset of flags section covering matching rules (exact, case-sensitive tags; whole-key globs where only * is special; tags OR key patterns), limits (31 values per list, 200 UTF-8 bytes per value), what happens when a selection is dropped by the SDK or ignored by Datadog (DD-Flag-Selection-Ignored reasons), FLAG_NOT_FOUND for flags outside the selection, initialFlagsConfiguration not being filtered, and fetchRulesConfiguration() support.
  • feature_flags/guide/proxy_sdk_traffic.md: the Browser tab notes that a proxy must pass through DD-Flag-Selection-Ignored and expose it with Access-Control-Expose-Headers.

Merge readiness

  • Ready for merge

The section names @datadog/openfeature-browser 2.2.0, the first release that includes flagSelection, as the minimum version.

AI assistance

Drafted with Claude Code from the SDK README and source; reviewed against the SDK behavior.

For Datadog employees:

  • ⚠️ Your branch name MUST follow the <name>/<description> convention and include the forward slash (/). If you've already created your PR with an incorrect branch name, please rename your branch and open a fresh PR.
  • 🤖 New: Comment with /review to run an automated check that catches common issues before a Documentation team member reviews your PR.

Additional notes

Other client SDK pages and the API reference are not part of this PR.

🤖 Generated with Claude Code

Add a Load a subset of flags section to the JavaScript client page and a proxy note for the DD-Flag-Selection-Ignored header.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the Guide Content impacting a guide label Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

mark-caii and others added 8 commits October 27, 2026 16:16
Nest the Load a subset of flags section under Initialize the provider, since flagSelection is set when the provider is created.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add the OpenFeature.getClient() call to the Evaluate flags outside the selection example, since client is otherwise first defined in the later Get a client section.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Set the minimum @datadog/openfeature-browser version to 2.2.0 and note that Datadog returns the full configuration without DD-Flag-Selection-Ignored when flag selection is not enabled for the organization.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Flag selection is rolling out globally, so the no-header case no longer refers to per-organization enablement.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remove the no-header case and state that flags outside the selection are not loaded.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lead with the risk that team tags change with ownership, and render it as a WARNING callout.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
List each limit on its own line so the 31-value limit is not read as a combined total.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Matches MAX_RULES_URL_BYTES and the too_many_values console error in @datadog/openfeature-browser 2.2.0.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@mark-caii
mark-caii marked this pull request as ready for review October 28, 2026 15:16
@mark-caii
mark-caii requested a review from a team as a code owner October 28, 2026 15:16
mark-caii and others added 3 commits October 28, 2026 15:32
State that too_many_values also covers selections too long for one request, document that empty selections load the full configuration silently, and scope the Access-Control-Expose-Headers requirement to cross-origin proxies.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add the two console error templates the browser SDK logs when it does not send a flag selection or when Datadog ignores it.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
State in one sentence that flagSelection does not filter configuration supplied with initialFlagsConfiguration.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@maycmlee maycmlee self-assigned this Oct 28, 2026
@maycmlee

Copy link
Copy Markdown
Contributor

Created DOCS-16170 for review

@maycmlee maycmlee added the editorial review Waiting on a more in-depth review label Oct 28, 2026
@maycmlee maycmlee removed their assignment Oct 28, 2026
});
{{< /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.


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:


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


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


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

@joepeeples joepeeples left a comment

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.

Thanks for this new content, @mark-caii! I flagged a few possible edits, and one overall structural suggestion: Consider moving Load a subset of flags under Configure browser provider options, as an H3. Where it sits now, it interrupts the basic setup flow with an optional, advanced feature.

Feel free to ping directly when ready for a quick re-review, thanks!


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

});
```

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

| Message | Cause |
| --- | --- |
| `Datadog Browser SDK: flagSelection was not sent (<REASON>: <LIMIT>). Loading the full flag configuration.` | The selection is malformed or exceeds a limit. |
| `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. |


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

});
{{< /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.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

editorial review Waiting on a more in-depth review Guide Content impacting a guide

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants