Create Quiz
When building a quiz you can add:
- Quiz questions with answer explanations:
SingleChoice,MultipleChoice, andTextEntry("Type the answer") - Quiz questions of type
Order,Flashcard,TypeRush, andGuessIt - Quiz questions the respondent answers by tapping an image:
TapAndFindandSpotTheDifference - A
QuestionBankblock that draws its questions from a question bank instead of carrying them itself - Form fields
- General blocks
- Multiple result pages: segment users based on their score
Properties every quiz question shares
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | SingleChoice, MultipleChoice, TextEntry, Order, Flashcard, TypeRush, GuessIt, TapAndFind, or SpotTheDifference | |
title | ✓ | string | The question | |
description | string | The description of the question | ||
media | string|object | An image, video, or social media embed shown with the question. Adding it automatically switches its display on. See Use media | ||
mediaOrientation | string | How that media is cropped: Settings, Wide, Square, Tall, or Original. Settings inherits the Riddle-wide setting | Settings | |
isRequired | boolean | If set to false, the user can skip the question. Not available on Flashcard | true | |
score | integer | The score the user gets for answering this question correctly. GuessIt has no score property at all - it is scored by the number of guesses used instead, see below | 1 |
Every question type supports a slightly different subset - the per-type tables below are exhaustive. A property a question type does not support is ignored rather than applied, so if a setting does not show up in the Riddle, check the table for that type first.
A question can hold at most 100 items/answers, and a whole build may reference at most 15 media files.
Scoring: per question or per item
score can be set on the question (all types) or on each individual item (SingleChoice, MultipleChoice, TypeRush, and each hotspot of a TapAndFind/SpotTheDifference) - setting it per item switches the question's scoring level to "per answer". Do not mix both levels within one question. Per-item score values must be >= 0 (>= 1 for TypeRush). Order is the exception: it is always scored as a single right/wrong answer for the whole sequence, so it only supports the question-level score - a per-item score is rejected.
Add Single/multiple choice questions
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to SingleChoice or MultipleChoice | |
title | ✓ | string | The question | |
items | ✓ | object | 2-100 answer options, each an object with its title and isCorrect - see item formats and the section below | |
description | string | The description of the question | ||
media | string|object | Media to display with the question. Adding it automatically switches its display on | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings | |
itemsShuffled | boolean | If set to true, the order of the items/choices will be shuffled | false | |
itemsRightOrWrong | boolean | If set to true, the items are visually marked as right or wrong after answering | true | |
isRequired | boolean | If set to false, the user can skip the question | true | |
score | integer | The score for answering this question correctly | 1 | |
layoutType | string | The layout of the items, either Rows or Columns | Rows | |
canWrapItems | boolean | Whether items may wrap onto a new line | true | |
isHeightFlexible | boolean | Whether each item's height flexes with its content | true | |
answerMediaOrientation | string | How the media of the individual answer items is cropped: Settings, Wide, Square, Tall, Original | Settings | |
isDescriptionVisible | boolean | Whether the per-answer descriptions are shown. One shared flag for the whole question, not one per answer: giving any item a description switches it on, sending false keeps the descriptions stored but hidden | derived from the items | |
explanation | object | An explanation object for the correct answer; learn more | ||
wrongExplanation | object | An explanation object for the incorrect answer; learn more | ||
explanationPosition | string | The position of the explanation (if given), either BelowAnswers or Overlay | Overlay | |
isExplanationMediaEnabled | boolean | Whether the explanation's own media is displayed | true | |
isExplanationEnabled | boolean | Explicitly switch the answer explanation on/off. Supplying explanation already switches it on; use isExplanationEnabled: false to disable it again while keeping the explanation content configured | ||
maxSelections | integer | MultipleChoice only: how many options may be picked at most (1-100) | 2 | |
hasUnlimitedSelections | boolean | MultipleChoice only: lift the maxSelections cap entirely | true | |
nrCorrectAnswersNeeded | integer | MultipleChoice only: how many correct options the user must pick to score | 1 | |
areRemainingVotesVisible | boolean | MultipleChoice only: show the user how many selections are left | true |
hint and showCorrectAnswerButton are not available on choice questions - they only exist on Order, TextEntry, TypeRush, TapAndFind, SpotTheDifference (hint) and Order, TextEntry, TapAndFind, SpotTheDifference (correct-answer button).
Item formats
Choice items follow the shared item formats: an array of objects, the answer text in title. What is specific here is isCorrect, which every answer carries:
{
"title": "The best noodles?",
"type": "SingleChoice",
"items": [
{ "title": "Spaghetti", "isCorrect": true },
{ "title": "Fusilli", "isCorrect": false }
]
}
An item takes more keys as soon as it carries a description, its own media, a score, or an explanation:
{
"title": "The best noodles?",
"type": "SingleChoice",
"items": [
{
"title": "Spaghetti",
"description": "The classic",
"media": "https://httpbin.io/image/jpeg",
"isCorrect": true
},
{
"title": "Fusilli",
"isCorrect": false
}
]
}
Each item object supports:
| Item property | Required | Type | Description | Default |
|---|---|---|---|---|
title | ✓ | string | The answer text | |
isCorrect | ✓ | boolean | Whether this answer is correct | |
description | string | A secondary line under the answer | ||
media | string|object | An image or video for this individual answer | ||
score | integer | The score for this answer (>= 0); switches the question to per-answer scoring | ||
explanation | object | An explanation shown for this specific answer; switches the question's explanations to per-answer |
At least one item must be marked as correct. In SingleChoice questions exactly one item may be correct - marking more than one returns an error.
Want to set answer explanations or the score per item? Learn more
Add "Type the answer" questions
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to TextEntry | |
title | ✓ | string | Title of the block | |
answers | ✓ | object | 1-100 accepted answers, each an object with the answer as its title - see item formats | |
description | string | Description of the block | ||
media | string|object | Media to display with the question. Adding it automatically switches its display on | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings | |
answerSuffix | string | A fixed suffix shown after the input, e.g. a unit like "km" | ||
isRequired | boolean | If set to false, the user can skip the question | true | |
hint | string | A hint shown with the question | ||
ignoreCase | boolean | Set to true to ignore the case of the answer (e.g. "hello" and "Hello" would be considered the same) | true | |
ignoreSpaces | boolean | Set to true to ignore spaces in the answer (e.g. "hello" and "h e l l o" would be considered the same) | true | |
lives | integer | How many attempts the user gets to answer the question | 3 | |
unlimitedLives | boolean | Set to true to give the user unlimited attempts to answer the question | false | |
livesText | string | The label for lives | Lives | |
livesIcon | string | The icon used for the lives widget: Heart, Numeric, or X | Heart | |
isLivesDisplayEnabled | boolean | Whether the remaining lives are shown to the user at all | true | |
showCorrectAnswerButton | boolean | Set to true to offer a "show correct answer" button | false | |
score | integer | The score the user gets for answering this question correctly | 1 | |
explanation | object | An explanation object for the correct answer; learn more | ||
wrongExplanation | object | An explanation object for the incorrect answer; learn more | ||
explanationPosition | string | The position of the explanation (if given), either BelowAnswers or Overlay | Overlay | |
isExplanationMediaEnabled | boolean | Whether the explanation's own media is displayed | true | |
isExplanationEnabled | boolean | Explicitly switch the answer explanation on/off. Supplying explanation already switches it on; use isExplanationEnabled: false to disable it again while keeping the explanation content configured |
answers follows the shared item formats: an accepted answer carries nothing but its text, so every entry is an object with just a title.
Example
{
"title": "Type 'hello' in either Italian, German, or French.",
"type": "TextEntry",
"answers": [
{ "title": "Ciao" },
{ "title": "Hallo" },
{ "title": "Bonjour" }
]
}
Optional properties
By default case and spaces are ignored, the user has three attempts, cannot skip the question, and receives no explanation. To change this behavior you can set ignoreCase, ignoreSpaces, lives, isRequired, and the explanation properties:
{
"title": "Type 'hello' in either Italian, German, or French.",
"type": "TextEntry",
"answers": [
{ "title": "Ciao" },
{ "title": "Hallo" },
{ "title": "Bonjour" }
],
"isRequired": false,
"ignoreCase": false,
"ignoreSpaces": false,
"lives": 1,
"livesText": "Attempts",
"livesIcon": "Numeric",
"explanation": {
"title": "Correct!",
"description": "Ciao, Hallo, and Bonjour all mean 'hello'"
},
"wrongExplanation": {
"title": "Incorrect!",
"description": "Ciao, Hallo, and Bonjour all mean 'hello'"
},
"explanationPosition": "BelowAnswers"
}
Add "Order it" questions
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to Order | |
title | ✓ | string | Title of the question | |
items | ✓ | object | 2-100 items in their correct order, each an object with its title plus an optional description or media - see item formats | |
description | string | Description of the question | ||
media | string|object | Media to display with the question. Adding it automatically switches its display on | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings | |
itemsShuffled | boolean | Whether the items are shuffled before the user starts | true | |
itemsShuffledOnWrong | boolean | Whether the items are re-shuffled after a wrong attempt | false | |
isRequired | boolean | If set to false, the user can skip the question | true | |
hint | string | A hint shown with the question | ||
score | integer | The score the user gets for answering this question correctly | 1 | |
layoutType | string | Set to Rows or Columns | Rows | |
rankFormat | string | Set to Number, Letter, or NumberEnum; setting it also switches the rank badges on | Number | |
isRankFormatEnabled | boolean | Explicitly switch the rank badges on/off. Setting rankFormat already switches them on; use isRankFormatEnabled: false to disable them again while keeping the format configured | ||
isRankReverseOrder | boolean | Whether the rank badges count down instead of up | false | |
answerMediaOrientation | string | How the media of the individual items is cropped: Settings, Wide, Square, Tall, Original | Settings | |
isDescriptionVisible | boolean | Whether the per-answer descriptions are shown. One shared flag for the whole question, not one per answer: giving any item a description switches it on, sending false keeps the descriptions stored but hidden | derived from the items | |
showCorrectAnswerButton | boolean | Set to true to show the correct answer button | false | |
guessesAreUnlimited | boolean | Set to true to allow unlimited guesses | false | |
guesses | integer | How many attempts the user gets | 3 | |
guessesIcon | string | Set to Heart, Numeric, or X | Heart | |
guessesDisplayLabel | string | The label shown next to the remaining guesses | Lives | |
guessesDisplayEnabled | boolean | Whether the guesses widget is shown at all | true | |
explanation | object | An explanation object for the correct answer; learn more | ||
wrongExplanation | object | An explanation object for the incorrect answer; learn more | ||
explanationPosition | string | The position of the explanation (if given), either BelowAnswers or Overlay | Overlay | |
isExplanationMediaEnabled | boolean | Whether the explanation's own media is displayed | true | |
isExplanationEnabled | boolean | Explicitly switch the answer explanation on/off. Supplying explanation already switches it on; use isExplanationEnabled: false to disable it again while keeping the explanation content configured | ||
upDownButtons | boolean | If set to true, up and down buttons are shown to change the order of the items instead of drag and drop | true |
Note: If you set guessesAreUnlimited to true, you must not also send guesses, guessesIcon or guessesDisplayLabel - doing so returns a validation error. guessesDisplayEnabled stays allowed either way. Sending guessesAreUnlimited: false alongside the other guesses properties is fine.
canWrapItems and isHeightFlexible are not available on Order questions. itemsRightOrWrong is not available either - an Order question is always scored as a single right/wrong answer for the whole sequence, so there is nothing to mark right/wrong per item.
Items are given in the correct order; the order you submit is the solution. They follow the shared item formats: an object per item, its text in title, plus description and media when the item carries more. Unlike SingleChoice/MultipleChoice, a per-item score or explanation is not supported on Order items - use the question-level score/explanation/wrongExplanation properties instead; learn more.
Example
An example with only the required options:
{
"title": "Order the following colors from lightest to darkest.",
"type": "Order",
"items": [
{ "title": "red" },
{ "title": "blue" },
{ "title": "green" }
]
}
An example with extensive configuration:
{
"title": "Order the following colors from lightest to darkest.",
"type": "Order",
"items": [
{ "title": "red" },
{ "title": "blue" },
{ "title": "green" }
],
"itemsShuffled": true,
"itemsShuffledOnWrong": true,
"isRequired": false,
"score": 5,
"layoutType": "Rows",
"rankFormat": "Number",
"isRankReverseOrder": true,
"showCorrectAnswerButton": true,
"guesses": 3,
"guessesIcon": "Heart",
"guessesDisplayLabel": "Cat lives",
"upDownButtons": false,
"explanation": {
"title": "Correct!",
"description": "The correct order is red, blue, green"
},
"wrongExplanation": {
"title": "Incorrect!",
"description": "The correct order is red, blue, green"
},
"explanationPosition": "BelowAnswers"
}
Add flashcard questions
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to Flashcard | |
title | ✓ | string | Title of the question | |
backside | ✓ | object | The content the user sees when flipping the flashcard; see below | |
description | string | Description of the question | ||
media | string|object | Media to display on the front of the flashcard | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings | |
hint | string | Hint for the question | ||
score | integer | The score the user gets for answering this question correctly | 1 | |
revealAnswerButtonText | string | Label of the button that flips the card | ||
gotItRightButtonText | string | Label of the "I got it right" button | ||
gotItWrongButtonText | string | Label of the "I got it wrong" button |
Flashcards have no answer explanations - explanation, wrongExplanation and explanationPosition do not apply. isRequired is not available either, and unlike other question types, media display cannot be toggled off.
Note: A Quiz that contains a Flashcard block only accepts linear logic - answer, condition, and score branching are all rejected. See Logic settings.
The backside object
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
title | ✓ | string | The answer shown on the back of the card | |
description | string | A longer explanation on the back | ||
media | string|object | Media shown on the back | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings |
Example
{
"title": "Capital of germany",
"description": "Germany is a country in Europe",
"hint": "Starts with a 'B'",
"type": "Flashcard",
"revealAnswerButtonText": "Flip it",
"gotItRightButtonText": "I knew it",
"gotItWrongButtonText": "No idea",
"backside": {
"title": "Berlin",
"description": "Berlin is the capital of Germany",
"media": "https://httpbin.io/image/png"
}
}
Add TypeRush questions
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to TypeRush | |
title | ✓ | string | Title of the question | |
items | ✓ | object | 1-100 items, each an object carrying its accepted answers plus an optional hint, media or score - see item formats and the section below | |
description | string | Description of the question | ||
media | string|object | Media to display with the question. Adding it automatically switches its display on | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings | |
rankFormat | string | Set to Number, Letter, or NumberEnum | Number | |
isRankFormatEnabled | boolean | Explicitly switch the rank badges on/off. Setting rankFormat already switches them on; use isRankFormatEnabled: false to disable them again while keeping the format configured | ||
isRankReverseOrder | boolean | Whether the rank badges count down instead of up | false | |
isRequired | boolean | If set to false, the user can skip the question | true | |
isIgnoringCase | boolean | Set to true to ignore the case of the answer (e.g. "hello" and "Hello" would be considered the same) | true | |
isIgnoringSpaces | boolean | Set to true to ignore spaces in the answer (e.g. "hello" and "h e l l o" would be considered the same) | true | |
isHintEnabled | boolean | Set to true to enable hints for each item | true | |
columnTitleHint | string | Header of the hint column | Hint | |
columnTitleAnswer | string | Header of the answer column | Answer | |
columnOrder | string | Which column comes first: HintFirst or AnswerFirst | HintFirst | |
isAnswerMediaVisible | boolean | Whether the media of the individual items is shown | true | |
answerMediaOrientation | string | How the media of the individual items is cropped: Settings, Wide, Square, Tall, Original | Settings | |
showCorrectAnswer | boolean | Whether the correct answers are revealed once the timer runs out | true | |
score | integer | The score the user gets for answering this question correctly; can either be set on question or answer level; must be >= 1 | 1 |
TypeRush questions have no answer explanations.
Item objects
items follows the shared item formats, with one specialty: a TypeRush item has no title of its own - its text is its accepted answer, so every entry carries an answers list instead. answers is a plain list of strings, one per accepted spelling.
| Item property | Required | Type | Description | Default |
|---|---|---|---|---|
answers | ✓ | string | All accepted spellings of this item | |
hint | string | The hint shown for this item | ||
media | string|object | An image or video for this item | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings | |
score | integer | The score for this item (>= 1); switches the question to per-answer scoring |
Example: simple TypeRush
{
"title": "Name Germany's three biggest cities",
"description": "A very hard question",
"type": "TypeRush",
"items": [
{ "answers": ["Berlin"] },
{ "answers": ["Hamburg"] },
{ "answers": ["Munich", "München"] }
],
"score": 5
}
Example: sophisticated TypeRush
Note: If you provide a score for the whole question, you must not provide scores for individual answers, and vice versa; if you try to set both, the API will return an error.
{
"title": "Name Germany's three biggest cities",
"description": "A very hard question",
"type": "TypeRush",
"items": [
{
"answers": ["Berlin"],
"score": 2,
"hint": "Starts with B"
},
{
"answers": ["Hamburg"],
"score": 3,
"hint": "Starts with H"
},
{
"answers": ["Munich", "München"],
"score": 4,
"hint": "Starts with M"
}
],
"rankFormat": "Letter",
"columnTitleHint": "Clue",
"columnTitleAnswer": "City",
"columnOrder": "AnswerFirst",
"isRequired": false,
"isIgnoringSpaces": false,
"isHintEnabled": false
}
Add GuessIt questions
"GuessIt" is a "guess the picture" question: the respondent sees an image (optionally blurred) and types their guess into a text field, with hints revealed as their guesses run out.
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to GuessIt | |
title | ✓ | string | Title of the question | |
acceptableAnswers | ✓ | object | 1-100 accepted answers, each an object with the answer as its title - see item formats | |
media | string|object | The picture the respondent has to guess. Adding it automatically switches its display on | ||
mode | string | Image or Text | Image | |
guessItTitle | string | A short label shown above the picture (distinct from the question's own title) | ||
guessesLabel | string | The label shown next to the remaining guesses | ||
numberOfGuesses | integer | How many attempts the respondent gets, 1-10 | 3 | |
hints | string | Hints that are visible from the start | ||
lockedHints | string | Hints that are progressively revealed as guesses are used up, at most 10. They occupy the last guess slots, in the order given - e.g. with 5 guesses and 2 locked hints, the first is revealed after the 4th failed guess and the second after the 5th | ||
hintPosition | string | OnImage or BelowImage | OnImage | |
imageBlurMode | string | Progressive (gets sharper with each failed guess), None, or Always | Progressive | |
showBlockTitle | boolean | Whether the question's own title is shown | true | |
showHowToPlay | boolean | Whether a "how to play" explainer is shown | true | |
isRequired | boolean | If set to false, the user can skip the question | true | |
isIgnoringCase | boolean | Set to true to ignore the case of the answer | true | |
isIgnoringSpaces | boolean | Set to true to ignore spaces in the answer | true |
acceptableAnswers follows the shared item formats: an accepted answer carries nothing but its text, so every entry is an object with just a title.
Note: GuessIt has no score property - unlike every other quiz question type, it is not scored on a fixed correct/incorrect basis but purely by how many guesses the respondent needed.
lockedHints cannot hold more entries than numberOfGuesses allows guess slots for - e.g. 3 locked hints require at least 3 guesses.
Example
{
"title": "Guess the city!",
"type": "GuessIt",
"media": "https://httpbin.io/image/png",
"acceptableAnswers": [
{ "title": "Berlin" }
],
"numberOfGuesses": 5,
"hints": ["It's a capital city"],
"lockedHints": ["It's in Germany", "It starts with a 'B'"],
"imageBlurMode": "Progressive"
}
Add "Tap and find" and "Spot the difference" questions
Both question types are answered by tapping an image instead of picking an answer: you place hotspots on the picture, and the respondent has to find them. TapAndFind uses a single image; SpotTheDifference shows a second one next to it (compareMedia) and the hotspots mark the differences between the two.
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to TapAndFind or SpotTheDifference | |
title | ✓ | string | Title of the question | |
hotspots | ✓ | object | The hotspots to find, at least 1 and at most 100; see Hotspot properties below - see item formats | |
description | string | Description of the question | ||
media | string|object | The image the respondent searches. Adding it automatically switches its display on | ||
compareMedia | string|object | SpotTheDifference only: the second, altered image shown next to media | ||
hint | string | A hint shown with the question | ||
isRequired | boolean | If set to false, the user can skip the question | true | |
lives | integer | How many taps the user gets | 3 | |
unlimitedLives | boolean | Set to true to give the user unlimited taps | false | |
livesText | string | The label for lives | Lives | |
livesIcon | string | The icon used for the lives widget: Heart, Numeric, or X | Heart | |
isLivesDisplayEnabled | boolean | Whether the remaining lives are shown to the user at all | true | |
showCorrectAnswerButton | boolean | Set to true to offer a "show correct answer" button, which reveals where the hotspots were | false | |
score | integer | The score the user gets for answering this question correctly | 1 | |
explanation | object | An explanation object for the correct answer; learn more | ||
wrongExplanation | object | An explanation object for the incorrect answer | ||
explanationPosition | string | The position of the explanation (if given), either BelowAnswers or Overlay | Overlay | |
isExplanationMediaEnabled | boolean | Whether the explanation's own media is displayed | true | |
isExplanationEnabled | boolean | Explicitly switch the answer explanation on/off. Supplying explanation already switches it on |
Neither type has a mediaOrientation - the image is always shown as-is, because the hotspots are placed on it.
Hotspot properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
shape | string | circle or rect | circle | |
x | number | Horizontal position in percent of the image, 0-100 | 10 | |
y | number | Vertical position in percent of the image, 0-100 | 15 | |
width | number | Width in percent of the image's width, 0-100. On a circle this is its diameter | 10 | |
height | number | Height in percent of the image's height, 0-100. Only on a rect - sending it on a circle is rejected | 10 | |
rotation | number | Rotation of the hotspot in degrees, -360 to 360 | 0 | |
score | integer | The score for finding this particular hotspot; setting it switches the question to per-answer scoring | 1 | |
description | string | An internal label for the hotspot | ||
explanation | object | An explanation shown for this particular hotspot; setting it switches the question's explanation mode to "per answer" |
All four geometry values are percentages of the image, never pixels, and fractional values such as 12.5 are allowed:
- On a
circle,x/yare its centre andwidthis its diameter; it has noheight. - On a
rect,x/yare its top-left corner, andwidth/heightare measured against the image's width and height respectively - so equal values on a non-square image are not a square.
Note: The hotspots are the answer, so a question without at least one is rejected. Scoring works exactly like it does for the items of a single/multiple choice question: set score on the question or on individual hotspots, not both - see scoring per question or per item.
Note: On SpotTheDifference the percentages are relative to the first image (media); use two images of the same size, since a difference has to sit in the same place on both.
Getting the coordinates right
Coordinates are the one thing a build configuration cannot get right on its own: whether a hotspot really sits on the thing it is supposed to mark only exists in relation to the pixels of your image. Build these questions in rounds - create the Riddle with a first guess, publish it, look at the published Riddle, then correct the hotspots that are off and publish again. Because hotspots merges by id (see editing a Riddle), a correction only has to mention the hotspots you are moving; do not delete and re-create them between rounds, or you throw away the ids you need.
Example
{
"title": "Find the three cats",
"type": "TapAndFind",
"media": "https://httpbin.io/image/png",
"hint": "One of them is behind the sofa.",
"lives": 5,
"livesIcon": "Numeric",
"hotspots": [
{ "x": 50, "y": 50, "width": 12.5, "description": "the tabby" },
{ "x": 20, "y": 70, "width": 10 },
{ "shape": "rect", "x": 62, "y": 12, "width": 15, "height": 20, "rotation": 15 }
]
}
{
"title": "Spot the five differences",
"type": "SpotTheDifference",
"media": "https://httpbin.io/image/png",
"compareMedia": "https://httpbin.io/image/webp",
"score": 5,
"hotspots": [
{ "x": 25, "y": 30, "width": 10 },
{ "shape": "rect", "x": 60, "y": 55, "width": 12, "height": 12 }
]
}
Add a Question Bank block
A QuestionBank block has no questions of its own: it draws them from a question bank - a reusable pool of questions managed outside the Riddle - when the Riddle is viewed. The build configuration only references the bank by its ID; it never creates or edits the bank's questions.
Properties
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
type | ✓ | string | Set to QuestionBank | |
questionBankId | ✓ | integer | The ID of an existing question bank whose riddleType is Quiz. A bank built for a Poll, a bank of a different project, or an ID that does not exist is rejected | |
title | string | A plain-text label for the block (no HTML) | ||
isRequired | boolean | Whether the drawn question has to be answered before continuing | true | |
randomizationType | string | TimeBased re-draws the questions every refreshInterval hours, None draws once and leaves the selection fixed | TimeBased | |
refreshInterval | integer | How often the draw is refreshed, in hours (minimum 1). Only meaningful together with randomizationType: "TimeBased" | 24 | |
questionBankBlocks | ✓ | object | One entry per block type the bank should draw into, see below. At least one entry is required - a block with none draws nothing at all |
The questionBankBlocks array
Each entry says which kind of question is drawn from the bank, and how it is filtered:
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
blockType | ✓ | string | SingleChoice, MultipleChoice, Order, TextEntry, TypeRush, or Flashcard. Each block type may appear at most once | |
isEnabled | boolean | Whether this block type actually draws from the bank | false | |
questionBankCriteria | object | Filters for the draw, see below. Omitted or empty means no filter - every item of that block type is eligible |
Each entry of questionBankCriteria:
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
category | ✓ | string | A category of the bank's items. Must be unique within one questionBankCriteria array | |
difficultyRange | integer | Exactly two integers [min, max] between 1 and 10, min <= max. An empty array means no difficulty filter | ||
maxNumberOfQuestions | integer | At most this many questions are drawn from that category. Omit it to compute a default automatically, never send an explicit null | computed automatically |
Note: Omitting maxNumberOfQuestions computes a default of at most 5, and at least 1, based on how many published items in the bank match the category and difficultyRange. Sending an explicit null is rejected.
Note: The bank's inventory is not checked while building. Asking for more questions than the bank actually holds is reported as a warning when publishing, never as a build error - call GET /question-bank/riddle-items/{riddleUUID}/{blockId} to see which items a block would draw right now.
Note: A QuestionBank block always draws from the bank's published state. A bank with unpublished changes keeps serving its last published questions, so publish the bank after changing its items.
Note: Sending questionBankBlocks when editing an existing Riddle replaces the whole array, like every other repeating collection of the Builder API.
Example
{
"type": "QuestionBank",
"title": "Random history question",
"questionBankId": 4711,
"randomizationType": "TimeBased",
"refreshInterval": 24,
"questionBankBlocks": [
{
"blockType": "SingleChoice",
"isEnabled": true,
"questionBankCriteria": [
{
"category": "History",
"difficultyRange": [3, 7],
"maxNumberOfQuestions": 5
}
]
}
]
}
Answer explanations
You can add an answer explanation to SingleChoice, MultipleChoice, TextEntry, Order, TapAndFind, and SpotTheDifference questions. Flashcard, TypeRush, and GuessIt questions do not support explanations.
To do this add an explanation object to the quiz question block configuration, consisting of:
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
title | ✓ | string | The title of the explanation | |
description | string | The description of the explanation | ||
media | string|object | A media URL to an image to display as part of the explanation | ||
mediaOrientation | string | Settings, Wide, Square, Tall, or Original | Settings |
If you wish to have an incorrect answer explanation, you can add the wrongExplanation with the same properties as explanation to the block. If only explanation is provided, it will be shown as an explanation for both correct and incorrect answers. Sending wrongExplanation without explanation returns an error.
To modify where the explanation is shown, you can set the explanationPosition property to either BelowAnswers or Overlay. If set to BelowAnswers, the explanation will be shown below the answer options. If set to Overlay, the explanation will be shown in an overlay on top of the question (default: Overlay). Use isExplanationMediaEnabled: false to keep an explanation's media out of the rendered Riddle without removing it. Use isExplanationEnabled: false to switch the whole explanation off without removing its configured content - useful if you want to temporarily disable it while keeping the text/title ready to re-enable later.
Example
{
"title": "Type 'hello' in either Italian, German, or French.",
"type": "TextEntry",
"answers": [
{ "title": "Ciao" },
{ "title": "Hallo" },
{ "title": "Bonjour" }
],
"explanation": {
"title": "My correct explanation",
"description": "My correct explanation description",
"media": "https://httpbin.io/image/webp"
},
"wrongExplanation": {
"title": "My wrong explanation",
"description": "My wrong explanation description",
"media": "https://httpbin.io/image/svg"
},
"explanationPosition": "BelowAnswers"
}
Answer explanations & scores per item
Just as in the Riddle Creator, you can provide an explanation and score for each item/answer individually. This works for SingleChoice and MultipleChoice, and for the hotspots of a TapAndFind/SpotTheDifference (TypeRush supports a per-item score, but no per-item explanation). Order does not support a per-item score or explanation - an Order question is always scored as a single right/wrong answer for the whole sequence, and a per-item score/explanation is rejected. Use the question-level score for scoring, and the question-level explanation/wrongExplanation for a single correct/incorrect explanation instead; learn more.
Note: You must either provide an explanation + a score for each answer, one for all, or none. Per-item score values must be >= 0; negative scores will be rejected.
Example SingleChoice object:
{
"title": "The best noodles?",
"type": "SingleChoice",
"explanationPosition": "BelowAnswers",
"items": [
{
"title": "Spaghetti",
"isCorrect": true,
"score": 2,
"explanation": {
"title": "Correct!",
"description": "Spaghetti is the best noodle"
}
},
{
"title": "Fusilli",
"isCorrect": false,
"score": 0,
"explanation": {
"title": "Incorrect!",
"description": "Spaghetti is the best noodle"
}
}
]
}
In the example above Spaghetti would be the correct choice and the user would get 2 points for selecting it. If they select Fusilli they would get 0 points and see the explanation "Spaghetti is the best noodle". This results in a maximum score of 2.
Note: The optional property explanationPosition must be set on the block level although the explanations are set on the item level.
Result pages
In a quiz you can specify multiple result pages to segment users based on their scores. For example users who score between 0-50% will see one result, users who score between 51-100% will see another result. Each result has a title, description, minPercentage, and maxPercentage property.
As there can be multiple results, we store the results in an array in build.results:
[
{
"title": "My result 0-30%",
"description": "Description 1",
"minPercentage": 0,
"maxPercentage": 50
},
{
"title": "My result 31-100%",
"description": "Description 2",
"minPercentage": 51,
"maxPercentage": 100
}
]
If you want to create complex result pages with texts, images, answered blocks, ... click here to learn how to build advanced result pages.
Full example
Example with all available blocks + options:
{
"type": "Quiz",
"build": {
"title": "Quiz example (Builder API)",
"blocks": [
{
"title": "What's the capital of Germany?",
"type": "SingleChoice",
"items": [
{ "title": "Berlin", "isCorrect": true },
{ "title": "Lissabon", "isCorrect": false },
{ "title": "Leipzig", "isCorrect": false }
],
"explanation": {
"title": "Correct!",
"description": "Berlin is the capital of Germany"
},
"wrongExplanation": {
"title": "Incorrect!",
"description": "Berlin is the capital of Germany"
}
},
{
"title": "What are valid colors in German?",
"type": "MultipleChoice",
"items": [
{ "title": "rot", "isCorrect": true },
{ "title": "schwarz", "isCorrect": true },
{ "title": "nero", "isCorrect": false }
],
"maxSelections": 2,
"hasUnlimitedSelections": false,
"nrCorrectAnswersNeeded": 2,
"explanation": {
"title": "Correct!",
"description": "Only 'rot' and 'schwarz' are valid colors in German"
}
},
{
"title": "Type 'hello' in either Italian, German, or French.",
"type": "TextEntry",
"answers": [
{ "title": "Ciao" },
{ "title": "Hallo" },
{ "title": "Bonjour" }
],
"explanation": {
"title": "Correct!",
"description": "Ciao, Hallo, and Bonjour all mean 'hello'"
},
"wrongExplanation": {
"title": "Incorrect!",
"description": "Ciao, Hallo, and Bonjour all mean 'hello'"
},
"ignoreCase": true,
"ignoreSpaces": true,
"lives": 3,
"livesIcon": "Heart"
},
{
"title": "Order the following colors from lightest to darkest.",
"type": "Order",
"items": [
{ "title": "red" },
{ "title": "blue" },
{ "title": "green" }
],
"itemsShuffled": true,
"guesses": 3
},
{
"title": "Capital of Germany",
"description": "Germany is a country in Europe",
"hint": "Starts with a 'B'",
"type": "Flashcard",
"backside": {
"title": "Berlin",
"description": "Berlin is the capital of Germany"
}
},
{
"title": "Name Germany's three biggest cities",
"description": "A very hard question",
"type": "TypeRush",
"items": [
{
"answers": ["Berlin"],
"score": 2,
"hint": "Starts with B"
},
{
"answers": ["Hamburg"],
"score": 3,
"hint": "Starts with H"
},
{
"answers": ["Munich"],
"score": 4,
"hint": "Starts with M"
}
],
"rankFormat": "Letter",
"columnTitleHint": "Clue",
"columnTitleAnswer": "City",
"columnOrder": "AnswerFirst"
},
{
"title": "Guess the city!",
"type": "GuessIt",
"media": "https://httpbin.io/image/png",
"acceptableAnswers": [
{ "title": "Berlin" }
],
"guessItTitle": "Which city is this?",
"numberOfGuesses": 5,
"hints": ["It's a capital city"],
"lockedHints": ["It's in Germany", "It starts with a 'B'"],
"hintPosition": "BelowImage",
"imageBlurMode": "Progressive",
"showHowToPlay": true
},
{
"title": "Find the three cats",
"type": "TapAndFind",
"media": "https://httpbin.io/image/png",
"hint": "One of them is behind the sofa.",
"lives": 5,
"livesIcon": "Numeric",
"hotspots": [
{ "x": 50, "y": 50, "width": 12.5, "description": "the tabby" },
{ "x": 20, "y": 70, "width": 10 },
{ "shape": "rect", "x": 62, "y": 12, "width": 15, "height": 20, "rotation": 15 }
]
},
{
"title": "Spot the differences",
"type": "SpotTheDifference",
"media": "https://httpbin.io/image/png",
"compareMedia": "https://httpbin.io/image/webp",
"score": 5,
"hotspots": [
{ "x": 25, "y": 30, "width": 10 },
{ "shape": "rect", "x": 60, "y": 55, "width": 12, "height": 12 }
]
}
],
"results": [
{
"title": "Not so good...",
"description": "There's room for improvement",
"minPercentage": 0,
"maxPercentage": 50
},
{
"title": "Well done!",
"description": "You're a winner",
"minPercentage": 51,
"maxPercentage": 100
}
]
}
}
Next steps
Now that you know the basics of building a quiz, you might want to learn how to:
- Add form fields to your Riddle
- Use the Ad block to monetize your Riddle or add Content blocks
- Connect your built Riddle to leaderboard(s)
- Define the publish settings: Enable DOI, email automation, add integrations, and more
- Define the preset and palette you want to use
- Define the logic / flow of your Riddle
- Build advanced result pages
- Add media, such as images, videos, and social media content
- Serve this Riddle through a Placeholder, so you can swap what an embed shows without changing the embed code
- Properties every quiz question shares
- Add Single/multiple choice questions
- Add "Type the answer" questions
- Add "Order it" questions
- Add flashcard questions
- Add TypeRush questions
- Add GuessIt questions
- Add "Tap and find" and "Spot the difference" questions
- Add a Question Bank block
- Answer explanations
- Answer explanations & scores per item
- Result pages
- Full example
- Next steps

