Guide

Segments

A segment is a named, reusable audience. Define "enterprise accounts" once, then reference it from every flag that cares, instead of copying the same conditions into a dozen rules.

How membership is decided

A segment has three inputs, checked in this order:

  1. Excluded keys — if the user's key is here, they are out. This wins over everything.
  2. Included keys — if the user's key is here, they are in.
  3. Rules — the user is in if any rule matches.

If none of the three puts them in, the user is not in the segment.

Segment rules are ORed; conditions within a rule are ANDed. This is the inverse of a flag's rule list, where the first match wins. It makes a segment a natural place to express "any of these audiences".

The user key

Included and excluded lists are matched against a single identifier resolved from the context: key, falling back to userId, then email. If none are present the key is empty and the user can never appear in either list, though rule-based membership still applies.

Not the same fallback as rollouts. Rollout bucketing reads userId then email, and ignores key. If you identify users with key alone, segments will work and percentage rollouts will bucket every one of those users identically. Send userId to be safe on both.

Referencing a segment from a flag

Use the segment_match operator. Its value is a segment key, or a list of them, and the user matches if they are in any of them. The attribute field is ignored by this operator; the convention is to set it to segmentKey to satisfy schema validation.

rule with a segment
{
  "name": "enterprise gets the new dashboard",
  "conditions": [
    { "attribute": "segmentKey", "operator": "segment_match", "value": "enterprise-accounts" }
  ],
  "serveValue": true,
  "rolloutPercentage": null
}

Combine a segment with ordinary conditions to narrow it further:

segment plus a condition
"conditions": [
  { "attribute": "segmentKey", "operator": "segment_match", "value": ["enterprise-accounts", "design-partners"] },
  { "attribute": "country",    "operator": "in",            "value": ["US", "CA"] }
]

Both conditions must hold: the user must be in either segment and in one of those countries.

Segment shape

CachedSegment
interface CachedSegment {
  key: string;
  /** Explicit user keys that are always in. */
  included: string[];
  /** Explicit user keys that are always out — takes precedence over included. */
  excluded: string[];
  /** Rule-based membership: a user matches if ANY rule matches. */
  rules: { conditions: RuleCondition[] }[];
}

Gotchas

  • An unknown segment key matches nobody. Referencing a segment that doesn't exist, or was deleted, evaluates to false rather than erroring. A typo therefore looks like an empty audience, not a failure.
  • A segment rule with no conditions matches nobody. This is deliberate: an empty rule silently including every user would be a dangerous default. Note this is the opposite of a flag rule with no conditions, which matches everyone.
  • Segments are environment-scoped, like flags. A segment in staging is a separate object from the one in production.

When to use one

  • Reuse: the same audience gates three or more flags.
  • Churn: the membership list changes more often than the flags that reference it, such as a beta cohort.
  • Allow/deny lists: a handful of named accounts, via included and excluded, with no conditions at all.

For a one-off audience used by a single flag, an inline condition is simpler and easier to read. Reach for a segment when the audience outlives the flag.