atrixANALYTICS

Feature flags

Rollouts, targeting, bucketing that is identical in every SDK, and local evaluation on your servers.

Flags are free on every plan. Local evaluation on your servers is unlimited; remote evaluation is fair-use.

Kinds

KindReturns
Booleantrue / false
Multivariatea variant key such as control or test, chosen by integer weights
Remote configa JSON payload

Each flag has a separate configuration per environment (production, preview, development), so you can turn something on in development without touching production. Every change is written to the project's annotations, so it shows up on charts.

Production is guarded

Making a production configuration live needs the named flags.production scope. A token or MCP client with only flags:write can prepare a flag but not ship it.

Targeting

Rules are checked in order; the first rule whose conditions all match decides the result. Conditions can read person properties, group properties and cohorts, with these operators: exact, in, is_not, not_in, icontains, not_icontains, regex, not_regex, gt, gte, lt, lte, is_date_before, is_date_after, semver_eq, semver_gt, semver_gte, semver_lt, semver_lte, is_set, is_not_set.

Bucketing

Rollouts are sticky. The bucket for a subject is:

sha1("<flag_key>.<salt><stickiness value>") → first 15 hex digits → ÷ 0xFFFFFFFFFFFFFFF → [0, 1)
in rollout when bucket < percentage / 100

Variants use the same hash with a separate variant salt. The result is bit-identical in every SDK and in the flag service: a shared set of test vectors (packages/contracts/test-vectors/flag-bucketing.json) runs in each implementation's test suite.

Stickiness is chosen per flag: distinct_id (default), device_id, person_id (server only) or a group type. When a device is identified, the service pins the person's bucket to the one their anonymous id already had, so nobody switches variant just by signing in.

Evaluating flags

import * as atrix from "@atrix.dev/analytics-web";

if (atrix.isEnabled("new-checkout")) {
  // …
}
const variant = atrix.getVariant("pricing");

Client SDKs load all flags once, cache them next to the identity, and reload on identify, group and reset. Pass bootstrap: { flags: {…} } to init for values before the first load.

Exposure events

Each flag read sends $feature_flag_called once per flag and value (per session on clients, per user on servers). Experiments count exposure from these events, so leave them on for any flag behind an experiment.

On this page