Logic Step
Route your workflow down different paths based on conditions you define.
The Logic step routes a workflow down different paths based on values from earlier steps. Branches are checked in array order. The first matching branch determines which step runs next. If no branch matches, an optional fallback branch determines the next step.
Use type: "new_logic_step" on the containing workflow step.
Before you begin
You need:
- An earlier step containing the values you want to evaluate.
- The exact name of that source step, supplied in its
descriptionproperty, and the UUID of each source field. - The exact name of each step that a branch can run next.
Put specific branches before broader branches because Logic checks them in array order. Add a fallback branch when the workflow must always continue.
The examples in the main guide show the workflow step's config value. The ready-to-use example at the bottom includes the complete step object.
Configure branches
| name | type | required | constraints | description |
|---|---|---|---|---|
branches | array | yes | items: branch | Ordered paths that the step can take. |
Branch properties
A branch contains the condition to check and, usually, the name of the step to run when it matches.
| name | type | required | constraints | description |
|---|---|---|---|---|
label | string | no | Name shown for the branch. Use a clear, distinct label so branches are easy to identify. | |
target | string | no | step name | Exact name of the step that runs when the branch matches. |
condition | object | yes | group | Rule that must match for the branch to run. See Build conditions. |
Although label and target are optional, include both on ordinary branches so the workflow is readable and the matching branch has a destination.
Fallback branch
A fallback branch catches sessions that do not match any ordinary branch. Its label must be exactly Fallback branch, including capitalization and spacing. Its condition must be an empty AND group:
{
"label": "Fallback branch",
"target": "Standard review",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": []
}
}Build conditions
A condition can compare two values, check whether one value is empty, or group several conditions. The type property identifies the kind of condition.
Each ordinary branch uses two group levels. The outer group contains inner groups, and each inner group contains comparisons or emptiness checks.
Comparison
A comparison checks a value from an earlier step against a fixed value or list of fixed values.
| name | type | required | constraints | description |
|---|---|---|---|---|
type | string | yes | binaryRule | Identifies a comparison. |
binaryOperator | string | yes | comparison operator | Comparison to perform. See Choose operators. |
leftOperand | string | yes | Usually a mapping placeholder for a field from an earlier step. | |
rightOperand | string | array | yes | string or string list | Fixed value to compare against. |
rightOperandmust contain a fixed value or list of fixed values. Comparing
one mapped field directly with another mapped field is not supported.
Emptiness check
An emptiness check tests whether a value is present. The operand is usually a mapping placeholder. null, a missing value, and an empty string are empty.
| name | type | required | constraints | description |
|---|---|---|---|---|
type | string | yes | unaryRule | Identifies a check. |
unaryOperator | string | yes | IS_EMPTY or IS_NOT_EMPTY | Check to perform. |
operand | string | yes | Value to check. |
Grouped conditions
A group combines conditions with AND or OR.
| name | type | required | constraints | description |
|---|---|---|---|---|
type | string | yes | group | Identifies a group. |
logicOperator | string | yes | AND or OR | With AND, all items must match. With OR, at least one must match. |
conditions | array | yes | Inner groups on an outer group, or checks on an inner group. |
For a non-empty ordinary branch:
- The outer group must contain only inner groups.
- Every inner group must use the same
logicOperator. - The inner operator must be different from the outer operator.
- Inner groups can contain only comparisons and emptiness checks.
An empty conditions array is accepted on an ordinary branch, but it does not define a useful conditional route. Use the exact fallback structure above when you need a catch-all path.
Route workflow paths
Compare a value
This branch checks whether a user's status equals "active":
{
"branches": [
{
"label": "Active user",
"target": "Active customer flow",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": [
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "binaryRule",
"binaryOperator": "EQUAL",
"leftOperand": "{{`User`.`status`}}",
"rightOperand": "active"
}
]
}
]
}
}
]
}Check for an empty value
This branch checks whether an email field is empty:
{
"branches": [
{
"label": "Check if email is empty",
"target": "Request email",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": [
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "unaryRule",
"unaryOperator": "IS_EMPTY",
"operand": "{{`User`.`email`}}"
}
]
}
]
}
}
]
}Combine multiple conditions
This example routes customers to one of three steps:
{
"branches": [
{
"label": "High-value active customer",
"target": "Premium customer flow",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": [
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "binaryRule",
"binaryOperator": "EQUAL",
"leftOperand": "{{`User`.`status`}}",
"rightOperand": "active"
}
]
},
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "binaryRule",
"binaryOperator": "GREATER_THAN_OR_EQUAL",
"leftOperand": "{{`User`.`credit`}}",
"rightOperand": "1000"
}
]
},
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "binaryRule",
"binaryOperator": "CONTAINS",
"leftOperand": "{{`User`.`kind`}}",
"rightOperand": "vip"
},
{
"type": "binaryRule",
"binaryOperator": "GREATER_THAN",
"leftOperand": "{{`User`.`credit`}}",
"rightOperand": "10000"
}
]
}
]
}
},
{
"label": "New customer with valid email",
"target": "Customer onboarding",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": [
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "binaryRule",
"binaryOperator": "EQUAL",
"leftOperand": "{{`Customer`.`kind`}}",
"rightOperand": "new"
}
]
},
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "unaryRule",
"unaryOperator": "IS_NOT_EMPTY",
"operand": "{{`Customer`.`email`}}"
}
]
}
]
}
},
{
"label": "Fallback branch",
"target": "Standard customer flow",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": []
}
}
]
}Choose operators
Comparison operators
| operator | applies to | description |
|---|---|---|
EQUAL | numeric, string, date, time, set | Left equals right. Numbers compare numerically ("2.0" equals "2"). Sets compare as order-independent exact matches. Datetimes compare by UTC instant. |
NOT_EQUAL | numeric, string, date, time, set | Left does not equal right. |
GREATER_THAN | numeric, date, time, datetime | Left is greater than right. Missing operands evaluate to false. |
LESS_THAN | numeric, date, time, datetime | Left is less than right. |
GREATER_THAN_OR_EQUAL | numeric, date, time, datetime | Left is greater than or equal to right. |
LESS_THAN_OR_EQUAL | numeric, date, time, datetime | Left is less than or equal to right. |
CONTAINS | string, set | String: left contains substring right. Set: left contains every value in right (extras on the left are allowed). |
NOT_CONTAINS | string, set | Inverse of CONTAINS. |
STARTS_WITH | string | Left starts with right. |
DOES_NOT_START_WITH | string | Left does not start with right. |
ENDS_WITH | string | Left ends with right. |
DOES_NOT_END_WITH | string | Left does not end with right. |
IS_LONGER_THAN | string vs numeric length | left.length > Number(right). Right is an integer length, not another string. |
IS_NOT_LONGER_THAN | string vs numeric length | left.length <= Number(right). |
IS_SHORTER_THAN | string vs numeric length | left.length < Number(right). |
IS_NOT_SHORTER_THAN | string vs numeric length | left.length >= Number(right). |
IS_LONGER_OR_EQUAL | string vs numeric length | left.length >= Number(right). |
IS_NOT_LONGER_OR_EQUAL | string vs numeric length | left.length < Number(right). |
IS_SHORTER_OR_EQUAL | string vs numeric length | left.length <= Number(right). |
IS_NOT_SHORTER_OR_EQUAL | string vs numeric length | left.length > Number(right). |
Keep these details in mind:
- String operators (
CONTAINS,STARTS_WITH,ENDS_WITH, and their opposites) use the string form of the value. - Ordering operators (
GREATER_THANand related operators) require comparable values: numbers, dates inYYYY-MM-DDformat, times inHH:mm:ssformat, or date and time values. Values that cannot be compared do not match. - Length operators compare the number of characters in
leftOperandwith a numericrightOperand. For example,"hello"with a right operand of"5"matchesIS_LONGER_OR_EQUAL. - When
rightOperandis an array,EQUAL,NOT_EQUAL,CONTAINS, andNOT_CONTAINStreat the values as sets. A single value is treated as a one-item set. Other operators convert the array to a comma-separated string.
Emptiness operators
| operator | description |
|---|---|
IS_EMPTY | Operand is null, missing, or an empty string. |
IS_NOT_EMPTY | Operand is not null, missing, or an empty string. |
Limitations and common errors
- No branch is taken. Add a fallback branch if the workflow must always continue.
- The wrong branch is taken. Branches run in array order. Put more specific conditions before broader conditions.
- The destination cannot be found. Set
targetto the exact step name. - A condition is rejected. Confirm that the configuration has exactly two group levels, that all inner groups use the same operator, and that the inner operator differs from the outer operator.
- A mapped value cannot be found. Confirm that the mapping uses the exact step name and field identifier from an earlier step.
Ready-to-use example
The complete step below routes premium customers to Premium customer details and sends everyone else to Standard customer details. Add both destination steps to the same workflow and replace the mapped field UUID with the customer type field from Customer intake.
{
"description": "Choose customer path",
"type": "new_logic_step",
"edges": [
{
"prev": "Customer intake"
}
],
"config": {
"branches": [
{
"label": "Premium customer",
"target": "Premium customer details",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": [
{
"type": "group",
"logicOperator": "OR",
"conditions": [
{
"type": "binaryRule",
"binaryOperator": "EQUAL",
"leftOperand": "{{`Customer intake`.`323e4567-e89b-42d3-a456-426614174002`}}",
"rightOperand": "premium"
}
]
}
]
}
},
{
"label": "Fallback branch",
"target": "Standard customer details",
"condition": {
"type": "group",
"logicOperator": "AND",
"conditions": []
}
}
]
}
}Updated 15 days ago
