Targeting rules
Serve different variants to different users with ordered rules, typed conditions, and segments.
Targeting rules decide which variant a user receives when a flag is on. Each environment has its own rules, so a rule in Development does not affect Production.
How rules work
A flag's rules form an ordered list. When a flag is on, Toggld checks each rule from top to bottom:
- A rule matches when all of its conditions match and all of its segment references match.
- The first matching rule wins. Toggld ignores the rules below it.
- If no rule matches, Toggld serves the default variant with the reason
STATIC.
When the flag is off, Toggld skips the rules and serves the off variant with the reason DISABLED.
Each rule serves one of these:
| Serve | Result | Reason |
|---|---|---|
| Fixed variant | One variant for every matching user. | TARGETING_MATCH |
| Rollout | A variant chosen by percentage. See Percentage rollouts. | SPLIT |
A rule with no conditions and no segments matches everyone. Use it as a catch-all at the end of the list.
Order matters
Put the most specific rules first. A broad rule near the top hides every rule below it.
Add a rule in the dashboard
- Open the flag and select the environment tab.
- In Who gets what, select Add rule. The new rule matches anyone and serves the default variant.
- Optionally, give the rule a name. The name is the rule's
description. - Select Condition. Enter the attribute, choose an operator, enter the value, and choose the value type.
- Optionally, select Segment to reference a segment. The button appears when the workspace has segments.
- Under Gets, choose a variant, or choose Split by percentage for a rollout.
- Drag the rule by its handle to the right position, or use Move up and Move down in the rule's ⋯ menu. The menu also has Duplicate and Delete rule.
- Select Save environment.
The path in Who gets what reads from top to bottom: the environment switch, then each rule in order, then Everyone else. When the switch is off, everyone gets the variant in If off.
After you save, select Test a user to see which variant a context gets, and why. The dialog uses the saved rules, not your draft.
Conditions
A condition compares one attribute of the evaluation context with a value.
{ "attribute": "plan", "operator": "eq", "value": "pro" }attributeis the name of a top-level context attribute, such asplanortargetingKey. Toggld does not read nested paths. The attributeuser.planmatches a context key that is literally nameduser.plan, not aplanfield inside auserobject.operatoris one of the operators below.valueis the operand. TheexistsandnotExistsoperators do not use it.
Operators
| Operator | Dashboard label | Matches when | Operand |
|---|---|---|---|
eq | is | The attribute equals the value. | Any JSON value |
ne | is not | The attribute is present and does not equal the value. | Any JSON value |
in | is one of | The attribute equals one item of the list. | JSON array |
notIn | is not one of | The attribute is present and equals no item of the list. | JSON array |
lt | < | The attribute is less than the value. | Number |
lte | ≤ | The attribute is less than or equal to the value. | Number |
gt | > | The attribute is greater than the value. | Number |
gte | ≥ | The attribute is greater than or equal to the value. | Number |
contains | contains | The attribute text contains the value. | String |
startsWith | starts with | The attribute text starts with the value. | String |
endsWith | ends with | The attribute text ends with the value. | String |
exists | is set | The attribute is present and not null. | None |
notExists | is not set | The attribute is missing or null. | None |
Notes:
- Missing attributes. If the context does not have the attribute, or its value is
null, every operator exceptexistsandnotExistsreturns no match. This includesneandnotIn. To match "not pro, or no plan at all", add a separate rule that usesnotExists. - Equality compares the JSON type and the value. Objects and arrays match when their contents are equal.
- Text operators are case-sensitive and work only on strings.
containschecks for a substring. It does not check whether an array contains an item. Useinfor that. - Number operators work only when both the attribute and the value are numbers.
Match the value type
Toggld never converts types. A condition matches only when the context sends the same JSON type as the rule.
| Rule value | Context value | Result |
|---|---|---|
"00123" (string) | "00123" (string) | Match |
"00123" (string) | 123 (number) | No match |
18 (number), operator gt | 21 (number) | Match |
18 (number), operator gt | "21" (string) | No match |
true (boolean) | "true" (string) | No match |
["001", "002"], operator in | "001" | Match |
Follow these rules to avoid surprises:
- Keep identifiers, such as account numbers and ZIP codes, as strings. A number loses leading zeros:
00123becomes123. - Send numbers as numbers when you compare them with
lt,lte,gt, orgte. - Send each attribute with the same type every time, in every service.
- In the dashboard, set the value type (Text, Number, Boolean, or JSON) to match what your code sends. Number and text operators always use their own type. For is one of and is not one of, type each value and press Enter or a comma. With the JSON value type, enter a JSON array instead, such as
["001", "002"]or[18, 25].
The API validates operands when you save. Number operators require a finite number, text operators require a string, and in and notIn require an array. Other operators require a value. Invalid rules return HTTP 422 with the error FlagValidationError.
Use segments in rules
A rule can reference segments. In the dashboard, select Segment in the rule and choose a segment. Choose in segment or not in segment.
{
"id": "beta-testers",
"conditions": [],
"segments": [{ "segment": "beta-testers" }],
"serve": { "type": "variant", "variant": "on" }
}- Segment references are combined with AND, both with each other and with the conditions.
"negate": truemeans "not in the segment".- Toggld rejects a rule that references a segment that does not exist.
- To target different audiences per environment, reference different segments in each environment's rules.
Rule format
In the API, targeting is an array of rules. This example serves on to beta users, then rolls out to 20% of everyone else:
{
"targeting": [
{
"id": "beta",
"description": "Beta plan",
"conditions": [{ "attribute": "plan", "operator": "eq", "value": "beta" }],
"serve": { "type": "variant", "variant": "on" }
},
{
"id": "rollout",
"conditions": [],
"serve": {
"type": "rollout",
"bucketBy": "targetingKey",
"splits": [
{ "variant": "on", "weight": 20 },
{ "variant": "off", "weight": 80 }
]
}
}
]
}| Field | Required | Description |
|---|---|---|
id | Yes | A rule identifier. Rollouts use it to assign buckets, so keep it stable. |
description | No | A note for people who read the rule. |
conditions | Yes | Conditions combined with AND. An empty array always matches. |
segments | No | Segment references combined with AND. |
serve | Yes | { "type": "variant", "variant": "…" } or a rollout. |
Every variant that a rule serves must exist in the same environment. Send the rules in a PATCH request to /api/v1/flags/{key} with a management key for the target environment. See Create and edit flags.