Overview
Targeting rules live in the dashboard. Your code sends an evaluation context (auserId 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
identify:
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.
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:
- Per-call
attributes identify()traitscreateClient({ context })- Browser timezone
- Edge geolocation
automaticTraits: false. Server clients (shipdit and Go) don’t infer location; pass it as an attribute. See Browser SDK.
Related
- Identify users
- Roll out a flag to a percentage of users
- Local evaluation
- Edge API for evaluation events and identity