Conditional logic
Use conditional logic to show or hide fields and layout blocks, route respondents between pages, or choose an ending. Conditions compare a field’s stored answer with a value.
Condition structure
A condition has a field name, an operator, and a value:
{ "field": "plan", "operator": "equals", "value": "Pro" }For several conditions, use an array that alternates condition objects with "AND" or "OR". Nest an array to group conditions.
Conditions are evaluated from left to right, with no operator precedence. For example, A OR B AND C means (A OR B) AND C. Use [A, "OR", [B, "AND", C]] to express A OR (B AND C). Evaluation short-circuits. An empty condition array evaluates to false, so visible_if: [] hides an element.
Operators
| Operator | Behaviour |
|---|---|
equals | Strict equality; "7" does not equal 7. |
not_equals | The opposite of equals. |
greater_than | Compares the stored value with >; strings and numbers are compared loosely. |
less_than | Compares the stored value with <. |
in | Checks whether the field value matches an item in value, which must be an array. A non-array value returns false. |
not_in | Checks that the field value does not match an item in value, which must be an array. A non-array value returns true. |
contains | For an array answer, checks for an exact element. Otherwise, checks for an exact match or substring. |
There are no >=, <=, or is_empty operators.
For a matrix field, use "<name>.<rowId>" to test one row. Use "<name>" to test all rows: positive operators match if any row matches; not_equals and not_in match if no row matches. The condition value can be a column ID or label.
Where to use conditions
- Set
visible_iforhide_ifon fields and layout blocks. An element is visible whenvisible_ifis true or absent, andhide_ifis false. Hidden fields skip validation, includingrequired. - Set
page.nextto route to a page, an ending, or the next page. Ago_totarget can be a page ID,"end", or"next". The first matching branch wins, thendefault, then"next". - Set
end_logicto choose an ending. The first matching branch wins, thendefault, then the first end page.
The only logic actions are show, hide, jump to a page, and choose an ending. Logic cannot reference CAPTCHA. CAPTCHA is a form setting. There are no set-value or calculate actions. Choices from pages skipped by the respondent’s path are dropped before the submission is stored.
Conditional endings
end_logic has a conditions array of branches with if and go_to, plus a top-level default ending target:
{
"mode": "page",
"pages": [
{
"type": "form",
"id": "p1",
"ui": [
{
"type": "single_select",
"name": "plan",
"label": "Which plan do you use?",
"options": ["Free", "Pro"],
"required": true
}
]
}
],
"end": [
{ "id": "e0", "type": "end", "ui": [] },
{ "id": "e1", "type": "end", "ui": [] }
],
"end_logic": {
"conditions": [
{
"if": [
{ "field": "plan", "operator": "equals", "value": "Pro" }
],
"go_to": "e1"
}
],
"default": "e0"
}
}Conditional endings and per-ending redirects run in page and tally modes, and when mode is unset. The server chooses the ending at submission after recomputing calculations. Malformed ending branches are skipped. Publishing rejects invalid end logic with INVALID_END_LOGIC when there are no endings, a target is missing, a redirect URL is invalid, or an ending is unreachable.
Examples
This config shows a follow-up field when the respondent selects the built-in Other choice as their contact preference. Built-in Other answers are stored as "Other: <text>", so the condition checks for the "Other:" substring:
{
"mode": "page",
"pages": [
{
"type": "form",
"id": "p1",
"ui": [
{
"type": "multiple_choice",
"name": "contact_preference",
"label": "How should we contact you?",
"options": ["Email", "Phone"],
"has_other": true,
"required": true
},
{
"type": "short_text_input",
"name": "contact_details",
"label": "What should we know about your preference?",
"visible_if": [
{
"field": "contact_preference",
"operator": "contains",
"value": "Other:"
}
]
}
]
}
],
"end": [
{
"id": "e0",
"type": "end",
"ui": []
}
]
}This config routes respondents to p2 when they select Pro and have more than 10 seats. Otherwise, they go to the next page:
{
"mode": "page",
"pages": [
{
"type": "form",
"id": "p1",
"ui": [
{
"type": "single_select",
"name": "plan",
"label": "Which plan do you use?",
"options": ["Free", "Pro"],
"required": true
},
{
"type": "number_input",
"name": "seats",
"label": "How many seats do you need?",
"required": true
}
],
"next": {
"conditions": [
{
"if": [
{
"field": "plan",
"operator": "equals",
"value": "Pro"
},
"AND",
{
"field": "seats",
"operator": "greater_than",
"value": 10
}
],
"go_to": "p2"
}
],
"default": "next"
}
},
{
"type": "form",
"id": "p2",
"ui": [
{
"type": "email_input",
"name": "work_email",
"label": "What is your work email?",
"required": true
}
]
}
],
"end": [
{
"id": "e0",
"type": "end",
"ui": []
}
]
}