Skip to content

Contexts

A context is the thing you pass to the SDK on every flag evaluation. It says “here is who, or what, is asking.” Targeting rules match against fields on the context.

client.evaluate("checkout-v2", false, {
targetingKey: "user-123",
user: { plan: "pro", email: "alice@example.com" },
});

A context always has a targeting key, a string that uniquely identifies the thing being evaluated. Everything else is structured under one or more context kinds:

{
targetingKey: "user-123",
user: { plan: "pro", email: "alice@example.com" },
organization: { id: "acme", region: "eu" },
device: { os: "ios", appVersion: "4.2.1" }
}

You can pass any combination of kinds. A flag rule can reference any kind that exists in the project’s context kinds registry.

The targeting key is special. It is what feat hashes for percentage rollouts: the same targeting key always falls into the same bucket while the rollout weights are unchanged. So:

  • Use a stable per-user identifier (your internal user ID, an email if it never changes).
  • Do not use a value that changes per request (a session ID, a request ID): users will hop between variations on every page load.

For anonymous traffic, mint a stable random ID and persist it (cookie, localStorage, mobile keychain) so a user keeps the same bucket across sessions. The web SDK does this for you when configured with anonymous: { storage: "localStorage" }.

A single context can carry several kinds. This is how you express “the user is X, and their organization is Y, and their device is Z” in one evaluation. A rule can reach into any of them:

user.plan is one of ["pro", "enterprise"]
organization.id is one of ["acme", "beta-org"]
device.os is "ios"

All three are AND’d within the rule. See Targeting rules for the rule structure.

A context with anonymous: true is treated as not-yet-identified. It still has a targeting key (you mint one), but targeting rules that depend on an identified user can be written to skip it. Useful for pre-login flows where you have nobody to attribute to yet.

Anonymous contexts are off by default per organization. Enable from Organization features.

The SDK sends nothing per evaluation. The whole context stays on your machine; evaluation runs locally against the datafile. The dashboard never sees individual user contexts unless you opt in to event reporting (which feat does not require).

That property is why feat does not retain a “contexts list” the way some platforms do: there is no inventory of users to leak.

The context shape lines up with the OpenFeature evaluation context. If you write your code against OpenFeature, the same context you pass through OpenFeature.setContext(...) works with the feat Provider unchanged.