Skip to main content

Overview

Targeting rules live in the dashboard. Your code sends an evaluation context (a userId and attributes); the SDK matches it against the rules in the snapshot, locally, with no network call. This page shows how to target one user, an email domain, or a plan.

Send attributes from code

In TypeScript session clients, you can also set them once with identify:
Rules can only match what you send. Attribute values are strings, numbers, booleans, or null. See EvaluationContext.

Add a rule

1

Open the flag

In the dashboard, open the project, click the flag, and select the environment.
2

Add a condition

Click Add rule, then Attribute. Fill in Attribute, Operator, and Value.
3

Choose what to serve

Set the rule’s Serve value, for example true.
4

Save

Click Save environment. Use the simulator on the flag page to check a user before you save.

Common rules

The userId attribute reads context.userId, so you don’t need to repeat it in attributes. String operators are case-sensitive: lowercase emails before you send them.

Operators

An attribute missing from the context matches only does not exist.

How values compare

is and is one of (and their negations) coerce numeric and boolean values, and otherwise use exact string equality. Ordered comparisons (gt, gte, lt, lte) compare numbers as numbers, then timestamps as instants, and otherwise strings by character code. Equivalent timestamps with different offsets match only in ordered comparisons, not string equality. Current SDK versions (shipdit 0.4+, @shipdit/convex 0.2+, and Go 0.1+) apply the same rules. Earlier TypeScript SDK versions use different timestamp parsing; see Upgrade to shipdit 0.4. Numbers. A string counts as a number when it’s a decimal (10, -2.5, .5, 1e3) or an unsigned 0x, 0o, or 0b literal (0x10). Surrounding whitespace is ignored. Underscores (1_000), hex floats (0x1p-2), signed hex (-0x10), and Infinity are not numbers, so they compare as strings. Timestamps. For ordered comparisons, both values must be strings in this format to compare as times: Dates are range-checked: 2026-02-30 and 2026-02-29 aren’t dates. Anything else, including times without a zone (2026-01-02T10:00), a space instead of T, or single-digit months (2026-1-2), compares as a string. Send timestamps in UTC with a Z to avoid surprises. Saving a flag or audience with a date-looking value outside this grammar in an ordered comparison returns the non-blocking x-shipd-rule-warning API header; the dashboard displays the warning. The rule still saves because string ordering is supported. Older TypeScript SDKs and Convex components can disagree with dashboard preview: check the TypeScript or Convex migration guide before upgrading.

Rule order

  • Rules run top to bottom. The first matching rule wins; later rules are not checked.
  • All conditions in one rule must match. Use Any of to match one of several conditions.
  • If no rule matches, the flag serves Fallthrough.
Put narrow rules (one user) above broad ones (a plan or a percentage). Reorder rules with the arrows on each rule.

Reuse targeting with audiences

An audience is a named set of conditions you can reference from any flag in the project. Create one under Audiences → New audience, then add an Audience condition to a rule with Membership set to is in or is not in. Audiences compile into the snapshot and evaluate locally from the same context attributes. You can also assert membership from code by passing audience keys:

Location traits in the browser

shipdit/client fills country, region, city, and timezone automatically, so you can add rules like country is US or timezone is America/Los_Angeles without sending them yourself. country is an ISO 3166-1 alpha-2 code; timezone is the browser’s IANA zone. When the same attribute comes from more than one place, the first source wins:
  1. Per-call attributes
  2. identify() traits
  3. createClient({ context })
  4. Browser timezone
  5. Edge geolocation
Turn it off with automaticTraits: false. Server clients (shipdit and Go) don’t infer location; pass it as an attribute. See Browser SDK.