Rule Operators
Rules control the flow of a questionnaire. After a user answers a question, the rules engine evaluates conditions to determine which question to show next.
Rule Components
Section titled “Rule Components”There are four rule component types available in the Strapi rules dynamic zone:
1. rule-comparison
Section titled “1. rule-comparison”A single condition with if/then/else branching.
| Field | Type | Description |
|---|---|---|
if |
condition | The comparison to evaluate |
then |
string | Question ID to navigate to if the condition is true |
else |
string | Question ID to navigate to if the condition is false |
Example: If the user’s country is Germany, go to the German-specific question; otherwise, go to the generic question.
{ "if": { "op": "equals", "variable": { "type": "static", "value": "DE" } }, "then": "germanSpecificQuestion", "else": "genericQuestion"}2. rule-group-comparison
Section titled “2. rule-group-comparison”Grouped conditions combined with AND/OR logic.
| Field | Type | Description |
|---|---|---|
condition |
enum | AND or OR |
comparisons |
array | Array of individual comparisons |
then |
string | Question ID if the group evaluates to true |
else |
string | Question ID if the group evaluates to false |
Example: If the user is over 18 AND lives in Germany, go to the standard flow.
{ "condition": "AND", "comparisons": [ { "op": "greaterThan", "key": "age", "variable": { "type": "static", "value": 18 } }, { "op": "equals", "key": "country", "variable": { "type": "static", "value": "DE" } } ], "then": "standardFlow", "else": "blockerScreen"}3. rule-date
Section titled “3. rule-date”Date-based comparison using dateDiff.
| Field | Type | Description |
|---|---|---|
op |
string | Always dateDiff |
variable.type |
enum | Unit: year, month, or day |
variable.value |
number | The threshold value to compare against |
variable.dir |
enum | Direction: gt (greater than) or lt (less than) |
variable.key |
string | Question ID containing the date answer |
variable.comparisonKey |
string | Optional: another question ID to compare against (instead of today’s date) |
then |
string | Question ID if true |
else |
string | Question ID if false |
Example: If the user’s date of birth is more than 65 years ago, route to a senior-specific flow.
{ "op": "dateDiff", "variable": { "type": "year", "value": 65, "dir": "gt", "key": "dateOfBirth" }, "then": "seniorFlow", "else": "standardFlow"}Example with comparisonKey: If the gap between two dates is less than 30 days.
{ "op": "dateDiff", "variable": { "type": "day", "value": 30, "dir": "lt", "key": "travelStartDate", "comparisonKey": "travelEndDate" }, "then": "shortTripFlow", "else": "longTripFlow"}4. rule-always
Section titled “4. rule-always”Unconditional routing — always navigates to the target question.
| Field | Type | Description |
|---|---|---|
then |
string | Question ID to always navigate to |
Example: After the intro screen, always go to the first question.
{ "then": "dateOfBirth"}Comparison Operators
Section titled “Comparison Operators”These operators are used inside rule-comparison and rule-group-comparison conditions.
Value Comparison
Section titled “Value Comparison”| Operator | Description | Example |
|---|---|---|
equals |
Deep equality check (=== semantics for primitives, deep compare for objects/arrays) |
Answer is exactly "DE" |
notEquals |
Deep inequality check | Answer is not "DE" |
same |
Loose equality (== semantics) |
Answer loosely matches 42 |
notSame |
Loose inequality (!= semantics) |
Answer does not loosely match 42 |
greaterThan |
Answer is greater than the value | Answer > 18 |
lessThan |
Answer is less than the value | Answer < 65 |
Collection Comparison
Section titled “Collection Comparison”| Operator | Description | Example |
|---|---|---|
isIn |
Answer is contained in the provided array | Answer is one of ["DE", "AT", "CH"] |
isNotIn |
Answer is not in the provided array | Answer is not in ["US", "UK"] |
contains |
Answer (string or array) contains the value | Answer contains "health" |
notContains |
Answer does not contain the value | Answer does not contain "excluded" |
Existence Check
Section titled “Existence Check”| Operator | Description | Example |
|---|---|---|
isDefined |
Answer is not null and not undefined |
User has answered the question |
isNotDefined |
Answer is null or undefined |
User has not answered the question |
Country-Specific
Section titled “Country-Specific”| Operator | Description |
|---|---|
equalsOrContainsCountryCode |
Answer equals or contains the specified country code |
notEqualOrContainsCountryCode |
Answer neither equals nor contains the specified country code |
doCountryCodesMatch |
The country codes in the answer match the specified codes |
doCountryCodesNotMatch |
The country codes in the answer do not match |
doAllCountryCodesMatch |
All country codes in the answer match (for multi-country questions) |
doAllCountryCodesNotMatch |
Not all country codes match |
Address-Specific
Section titled “Address-Specific”| Operator | Description |
|---|---|
doesAddressMatch |
Address answer matches the comparison address |
doesAddressNotMatch |
Address answer does not match |
Unconditional
Section titled “Unconditional”| Operator | Description |
|---|---|
always |
Always evaluates to true. Use for unconditional routing. |
Variable Types
Section titled “Variable Types”Each comparison operator uses a variable to define what the answer is compared against.
Static Variable
Section titled “Static Variable”Compare the answer against a fixed, hardcoded value.
{ "op": "equals", "variable": { "type": "static", "value": "DE" }}| Field | Type | Description |
|---|---|---|
type |
string | "static" |
value |
any | The fixed value to compare against (string, number, boolean, array, or object) |
Dynamic Variable
Section titled “Dynamic Variable”Compare the answer against another question’s answer.
{ "op": "equals", "variable": { "type": "dynamic", "key": "partnerCountry" }}| Field | Type | Description |
|---|---|---|
type |
string | "dynamic" |
key |
string | The question ID whose answer to use as the comparison value |
Use case: “If the user’s country of residence matches their country of origin, skip the visa question.”
Custom Functions (Code Only)
Section titled “Custom Functions (Code Only)”For cases where CMS operators are insufficient, rules can include custom JavaScript functions defined in app code. These are not configurable from Strapi.
Signature:
(answer: any, answers: Record<string, any>, questionId: string) => boolean| Parameter | Description |
|---|---|
answer |
The current question’s answer |
answers |
All answers collected so far (keyed by question ID) |
questionId |
The current question’s ID |
Custom functions are defined in the questionnaire’s TypeScript file and referenced by the rules engine at runtime.
Evaluation Order
Section titled “Evaluation Order”Rules are evaluated in the order they appear in Strapi. The first matching rule determines the next question. If no rule matches, the questionnaire follows the default question order (as defined in the questionList).
See also
Section titled “See also”- Configure Rules – step-by-step guide for adding rules in Strapi
- Adding Conditional Rules – hands-on tutorial with branching logic
- Rule Evaluation – how the rule engine processes conditions and the “else” pitfall