Logic settings
Just like in the Riddle creator, you can set up custom logic flows for your Riddles using the Builder API.
Custom logic flows are available for the following Riddle types via API:
Currently, only branching by answers for SingleChoice, MultipleChoice, and standalone Form Dropdown fields is supported. The following will be added soon:
- Branching by block score or total score
- Branching by a data layer variable
Any other suggestions? Please get in touch via support chat or send an email to hello@riddle.com.
Default logic
When you create a Riddle via the Builder API without specifying any logic settings, the Riddle will have a default linear logic flow. This means that the blocks will be shown in the exact order they are defined in the blocks
array of the build configuration.
Prerequisites
To be able to work with the logic settings efficiently, it is advised to read about assigning custom IDs to blocks and answer items first. This makes it easier to reference the blocks and answer items in the following logic settings.
Logic settings structure / properties
The logic settings are defined in the logic
property in the build
configuration, next to the blocks
and result
/results
properties:
{
"type": "Quiz",
"build": {
"title": "My quiz with logic",
"blocks": [
"...",
"...",
"..."
],
"results": [
"..."
],
"logic": {
"...logic tree structure..."
}
}
}
The logic settings structure can be compared to a "tree" where the root of the tree is the start block, and each branch represents a possible path through the Riddle based on user interactions. This means it can nest indefinitely, as long as there are available blocks in the build configuration.
You can use two types of branching:
Linear 'branching'
Property | Required | Type | Description | Default |
---|---|---|---|---|
blockId | ✓ | integer | The ID of the block where this logic layer starts. Can reference any block, for example even Content . | |
branchingType | string | The type of branching to use. For linear branching it is set to linear , but can also be omitted due to being the default value. | linear | |
next | object | An object defining the next block to show after the block defined in blockId has been completed. |
Example: Sequence of 4 linear blocks
{
"blockId": 1,
"next": {
"blockId": 2,
"next": {
"blockId": 3,
"next": {
"blockId": 4
}
}
}
}
Answer branching
Property | Required | Type | Description | Default |
---|---|---|---|---|
blockId | ✓ | integer | The ID of the block where this logic layer starts. Can only reference blocks which support branching (currently SingleChoice, MultipleChoice, and standalone Form Dropdown fields). | |
branchingType | ✓ | string | The type of branching to use. For answer branching, it is set to answer . | linear |
rules | ✓ | object | An array of rule objects defining the branching logic. To see the structure of each rule, see below. |
Defining rules
Note: Each rule itself is also either a linear or answer branching, meaning it can contain a next
OR rules
property to define what happens after the block defined in blockId
has been completed.
Properties exclusive to the rule object:
Property | Required | Type | Description | Default |
---|---|---|---|---|
answers | ✓ | string|int | An array of answers that trigger this rule. You can use either the answer text or the given answer ID to identify the answer. |
Example: Answer branching with linear next
{
"answers": ["Answer 1", "Answer 2"],
"blockId": 2,
"next": {
"blockId": 3
}
}
In spoken form: If the user selects "Answer 1" or "Answer 2" show block with ID 2, then after completing that block, show block with ID 3.
Example: Answer branching, followed by answer branching / rules
{
"answers": ["Answer 1", "Answer 2"],
"blockId": 2,
"branchingType": "answer",
"rules": [
"..."
]
}
In spoken form: If the user selects "Answer 1" or "Answer 2" show block with ID 2, then after completing that block, follow the rules defined in the rules
array (and so on).
Example: First linear branching, then answer branching, then linear branching
{
"blockId": 1,
"next": {
"blockId": 2,
"branchingType": "answer",
"rules": [
{
"answers": ["Answer 1"],
"blockId": 3,
"next": {
"blockId": 4
}
},
{
"answers": ["Answer 2"],
"blockId": 5
}
]
}
}
In spoken form: Start with block ID 1, then show block ID 2. If the user selects "Answer 1", show block ID 3, then block ID 4. If the user selects "Answer 2", show block ID 5.
Pitfalls
Building the logic settings can be tricky. Here are some tips to avoid common pitfalls:
- Result blocks are not part of the logic tree in the API. Instead, they will always be shown at the end of the Riddle logic tree, regardless of the path taken. An end of the logic tree can be defined by adding a logic layer with no
next
property or with thenext
property set to null. - Make sure to use custom IDs for blocks and answers to make it easier to reference them in the logic settings.
Troubleshooting / Error codes
The logic settings throws unique error codes which can only occur in this context.
Not sure how exception handling works? Check out the basic API exception handling.
RIDDLE_BUILDER_BLOCK_PROPERTY_LOGIC_CIRCULAR_REFERENCE
A circular reference was detected in the logic settings. This means that a block is referenced again going 'up' the logic tree, which would create an infinite loop.
Example faulty logic settings:
{
"blockId": 1,
"next": {
"blockId": 2,
"next": {
"blockId": 1
}
}
}
RIDDLE_BUILDER_BLOCK_PROPERTY_LOGIC_INVALID_RULE
The answers
provided in an answer branching rule object is either empty or references answers that do not exist in the corresponding block's items
array.
Example faulty logic settings:
{
"blockId": 1,
"branchingType": "answer",
"rules": [
{
"answers": [], // empty answers array
"blockId": 2
},
{
"answers": ["Non-existing answer"], // answer does not exist in block's items
"blockId": 3
}
]
}
RIDDLE_BUILDER_BLOCK_PROPERTY_LOGIC_NON_UNIQUE_RULES
The answers
provided in an answer branching rule object are not unique. This means that the same answer is referenced in multiple rules of the same logic layer.
Example faulty logic settings:
{
"blockId": 1,
"branchingType": "answer",
"rules": [
{
"answers": ["Answer 1", "Answer 2"],
"blockId": 2
},
{
"answers": ["Answer 2", "Answer 3"], // "Answer 2" is referenced twice
"blockId": 3
}
]
}
RIDDLE_BUILDER_BLOCK_PROPERTY_LOGIC_NON_EXISTING_BLOCK
A blockId
in the logic settings references a block that does not exist in the blocks
array of the build configuration.
Example faulty logic settings:
{
"blockId": 999, // block with ID 999 does not exist in blocks array
"next": {
"blockId": 2
}
}
RIDDLE_BUILDER_BLOCK_PROPERTY_LOGIC_UNUSED_BLOCKS
Some blocks defined in the blocks
array of the build configuration are not referenced in the logic settings. This means that there is no possible way for a user to reach these blocks when taking the Riddle. In the Riddle Creator this is indicated by a warning icon in the publish step, in the Builder API this results in an error to avoid building Riddles with unnecessary/unused blocks.
RIDDLE_BUILDER_BLOCK_PROPERTY_LOGIC_LINEAR_ONLY_ALLOWED
This can only happen in one scenario: You are trying to use answer branching in a Quiz with Flashcard blocks: This is disallowed as Flashcards have complex logic themselves which does not work with non-linear logic.
Full example 1: Quiz with answer branching on quiz questions
Riddle build configuration (without logic settings in first step):
{
"type": "Quiz",
"build": {
"title": "Logic example (Builder API)",
"blocks": [
{
"id": 1,
"title": "What's the capital of Germany?",
"type": "SingleChoice",
"items": {
"Berlin": true,
"Lissabon": false,
"Leipzig": false
}
},
{
"id": 2,
"title": "What are valid colors in German?",
"type": "MultipleChoice",
"items": {
"rot": true,
"schwarz": true,
"nero": false
}
},
{
"id": 3,
"title": "Order the following colors from lightest to darkest.",
"type": "Order",
"items": [
"red",
"blue",
"green"
]
}
],
"results": [
{
"title": "Thanks for taking the quiz!",
"minPercentage": 0,
"maxPercentage": 100
}
]
}
}
The quiz above consists of three question blocks and one result block. For this example we want to branch based on the "What's the capital of Germany?" question. If the user answers "Berlin", we want to show the second question ("What are valid colors in German?"). If the user answers "Lissabon" or "Leipzig", we want to skip the second question and go directly to the third question ("Order the following colors from lightest to darkest.").
The logic tree / settings then look like this:
{
"blockId": 1,
"branchingType": "answer",
"rules": [
{
"answers": ["Berlin"],
"blockId": 2,
"next": {
"blockId": 3,
}
},
{
"answers": ["Lissabon", "Leipzig"],
"blockId": 3,
}
]
}
Note: result blocks are not part of the logic tree in the API. Instead, they will always be shown at the end of the Riddle logic tree, regardless of the path taken. An end of the logic tree can be defined by adding a logic layer with no next
property or with the next
property set to null.
Optional: Referencing answers by ID
As with the blocks
, the answer items can also be referenced by their ID instead of the answer text which makes it less confusing and more deterministic when creating logic rules for complex build configurations. Learn more
Step by step guide to convert from answer text to answer IDs:
- Add explicit IDs to the answers in the
items
property of the SingleChoice question block:
{
"id": 1,
"title": "What's the capital of Germany?",
"type": "SingleChoice",
"items": [
{"id": 11, "title": "Berlin", "isCorrect": true},
{"id": 22, "title": "Lissabon", "isCorrect": false},
{"id": 33, "title": "Leipzig", "isCorrect": false}
]
}
- Use the answer IDs (i.e. 11, 22, 23) in the logic settings instead of the answer text:
{
"blockId": 1,
"branchingType": "answer",
"rules": [
{
"answers": [11],
"blockId": 2,
"next": {
"blockId": 3
}
},
{
"answers": [22, 33],
"blockId": 3
}
]
}
Full example
Putting it all together, the full request body to create the quiz with the described logic looks like this:
{
"type": "Quiz",
"build": {
"title": "Logic example (Builder API)",
"blocks": [
{
"id": 1,
"title": "What's the capital of Germany?",
"type": "SingleChoice",
"items": {
"Berlin": true,
"Lissabon": false,
"Leipzig": false
}
},
{
"id": 2,
"title": "What are valid colors in German?",
"type": "MultipleChoice",
"items": {
"rot": true,
"schwarz": true,
"nero": false
},
"explanation": {
"title": "Correct!",
"description": "Only 'rot' and 'schwarz' are valid colors in German"
}
},
{
"id": 3,
"title": "Order the following colors from lightest to darkest.",
"type": "Order",
"items": [
"red",
"blue",
"green"
],
"itemsShuffled": true,
"guesses": 3
}
],
"logic": {
"blockId": 1,
"branchingType": "answer",
"rules": [
{
"answers": ["Berlin"],
"blockId": 2,
"next": {
"blockId": 3
}
},
{
"answers": ["Lissabon", "Leipzig"],
"blockId": 3
}
]
},
"results": [
{
"title": "Thanks for taking the quiz!",
"minPercentage": 0,
"maxPercentage": 100
}
]
},
}
Full example 2: Poll with branching on a standalone form dropdown field
In this example, we have a poll that starts with a standalone form dropdown field asking the user to select their favorite programming language. Based on the user's selection, we will branch to different questions.
{
"type": "Poll",
"build": {
"title": "Programming Language Quiz",
"blocks": [
{
"id": 1,
"title": "Select your favorite programming language:",
"type": "FormField",
"fieldType": "Dropdown",
"items": [
"Python",
"JavaScript",
"Java"
]
},
{
"id": 2,
"title": "Why do you like Python?",
"type": "SingleChoice",
"items": [
"Easy to learn",
"Great libraries",
"Versatile"
]
},
{
"id": 3,
"title": "Why do you like JavaScript?",
"type": "SingleChoice",
"items": [
"Web development",
"Versatile",
"Large community"
]
},
{
"id": 4,
"title": "Why do you like Java?",
"type": "SingleChoice",
"items": [
"Platform independence",
"Strong typing",
"Enterprise use"
]
}
],
"logic": {
"blockId": 1,
"branchingType": "answer",
"rules": [
{
"answers": ["Python"],
"blockId": 2,
},
{
"answers": ["JavaScript"],
"blockId": 3,
},
{
"answers": ["Java"],
"blockId": 4,
}
]
},
"results": [
{
"title": "Thanks for sharing your preferences!",
"minPercentage": 0,
"maxPercentage": 100
}
]
}
}