Five ways to get content into QuizBuilder — from a simple CSV spreadsheet to AI-assisted bulk creation — plus how to run a live trivia game.
The fastest way to get a spelling bee into QuizBuilder is to import a JSON test bundle. Each word gets one block: an audio context (uploaded separately) and a short-text question auto-scored against the correct spelling.
A QuizBuilder test export is a single JSON object. The blocks array holds groups of questions.
For a spelling bee each block has one word, one optional audio context, and one short_text question.
{
"title": "Grade 4 Spelling Bee",
"description": "Listen and spell each word correctly.",
"question_count_mode": "all",
"show_correct_answers": true,
"blocks": [
{
"title": "Word 1",
"context_json": null, // audio uploaded after import
"questions": [
{
"type": "short_text",
"points": 1,
"review_required": false,
"prompt_json": {
"type": "doc",
"content": [{ "type": "paragraph",
"content": [{ "type": "text", "text": "Type the word you hear." }] }]
},
"correct_answer": "necessary",
"options_json": null
}
]
},
{
"title": "Word 2",
"context_json": null,
"questions": [
{
"type": "short_text",
"points": 1,
"review_required": false,
"prompt_json": {
"type": "doc",
"content": [{ "type": "paragraph",
"content": [{ "type": "text", "text": "Type the word you hear." }] }]
},
"correct_answer": "receive",
"options_json": null
}
]
}
]
}review_required: false on short_text questions to enable instant auto-scoring.
QuizBuilder compares the answer case-insensitively and trims whitespace.
Go to Tests → Import, select your JSON file, and click Import. QuizBuilder creates the test with all blocks and questions. The test is saved as a draft — no takers can access it yet.
Open the test editor. For each block, click the Upload audio / video link in the block context area and select the corresponding MP3 file. The file is uploaded and stored server-side.
The context area will change to show a media badge (♪ audio/mpeg) with Replace and Remove buttons — confirming the audio is attached.
Set the test status to Published, choose your access mode (open link, access codes, or registered users), and copy the shareable URL. Takers hear the audio, type the word, and see their score immediately on submission.
If you already have questions in a spreadsheet (Excel, Google Sheets, Numbers), you can export as CSV and import directly into QuizBuilder. One test is created automatically, with questions grouped by the optional block column.
Your CSV must have a header row with these columns. All except type and prompt are optional.
type # multiple_choice | multiple_select | true_false | short_text | long_text prompt # question text (plain text) options # choices separated by | for mc/ms, e.g. Paris|London|Berlin correct_answer # single value for mc/tf, comma-list for ms, plain text for short_text points # integer, default 1 tags # comma-separated tags (optional) block # block/group title to organize questions (optional)
type,prompt,options,correct_answer,points,tags,block multiple_choice,What is the capital of France?,Paris|London|Berlin|Madrid,Paris,2,geography,Europe multiple_choice,Which country is the largest by area?,Russia|Canada|USA|China,Russia,2,geography,World true_false,The Amazon river is in Africa.,,false,1,geography,Americas multiple_select,"Which are continents? (select all)","Africa|Europe|Pacific|Antarctica","Africa,Europe,Antarctica",3,geography,World short_text,Spell the name of the capital of Japan.,,Tokyo,1,spelling,Asia
multiple_choice / true_false: the exact option value, e.g. Paris or false
multiple_select: comma-separated values, e.g. Africa,Europe,Antarctica
short_text: the expected text (auto-scored, case-insensitive)
long_text: leave blank — always goes to manual review
In the admin panel, go to Tests and click the ↑ CSV button in the top-right corner.
Select your .csv file. QuizBuilder creates a new unpublished test named after the filename, with all questions grouped into blocks matching the block column.
After import: review the test, edit any question that needs adjusting, then click Publish to make it live.
seed_audio.py
The examples/seed_audio.py script automates the full pipeline: it creates a test, adds a block per word,
generates or loads an MP3 for each word, uploads it, and wires the audio to the block — all via the QuizBuilder REST API.
No manual clicking required.
# Inside the QuizBuilder/examples/ directory
pip install requests gtts
requests calls the QuizBuilder API. gtts (Google Text-to-Speech) generates MP3 files
on the fly when no local audio is available. If you have your own MP3s, gtts is optional.
The simplest invocation — just provide your QuizBuilder URL, admin credentials, and a word list. The script calls Google TTS for each word and uploads the result.
python seed_audio.py \ --url http://localhost:8000 \ --email admin@example.com \ --password your_password \ --title "Grade 5 Spelling Bee" \ --words necessary receive separate beautiful \ conscience occurrence rhythm
Place your MP3 files in a folder. Each file must be named exactly as the word with an
.mp3 extension (e.g. necessary.mp3).
Pass the folder with --local-audio:
# Folder structure: # spelling_bee_audio/ # necessary.mp3 # receive.mp3 # separate.mp3 # ... python seed_audio.py \ --url http://localhost:8000 \ --email admin@example.com \ --password your_password \ --title "Grade 5 Spelling Bee" \ --local-audio ./spelling_bee_audio \ --words necessary receive separate beautiful \ conscience occurrence rhythm
When --local-audio is set the script checks the folder first. If the file exists it's used directly;
if not, it falls back to gTTS. This lets you use professional recordings for some words and synthesised
speech for the rest.
For each word the script:
1. Creates a block titled with the word number (e.g. "Word 1").
2. Uploads the MP3 to /api/v1/media/ and gets back a media_file_id.
3. Sets the block's context_json to an audio node referencing that file ID.
4. Adds a short_text question with correct_answer set to the word.
When done, the test is ready to publish — open it in the admin panel, review, and set to Published.
Any capable AI (Claude, ChatGPT, Gemini) can generate a complete QuizBuilder-compatible JSON file from a description. You describe the test; the AI produces the JSON; you import it. This works for spelling bees, multiple-choice exams, reading comprehension — anything QuizBuilder supports.
The AI needs to know the exact JSON structure QuizBuilder expects. Paste the following context at the top of your prompt:
You are generating test data for the QuizBuilder self-hosted assessment platform. Output a single valid JSON object matching this schema exactly:
{
"title": "string",
"description": "string | null",
"draw_count": null,
"time_limit_minutes": "integer | null",
"show_correct_answers": "at_end" | "never" | "per_question",
"blocks": [
{
"title": "string",
"context_json": null,
"questions": [
{
"type": "multiple_choice | multiple_select | true_false |
short_text | long_text | file_upload",
"points": integer,
"review_required": true | false,
"prompt_json": {
"type": "doc",
"content": [{ "type": "paragraph",
"content": [{ "type": "text", "text": "question text here" }] }]
},
"correct_answer": "string | array | null",
"options_json": ["Option A", "Option B"] | null
}
]
}
]
}Rules:
"questions" array."options_json" — never "options".show_correct_answers must be the string "at_end", "never", or "per_question" — not true/false.multiple_choice: set options_json to ["Option A", "Option B", ...] and correct_answer to the exact text of the correct option.multiple_select: set options_json to a list and correct_answer to a JSON array, e.g. ["A", "C"].true_false: set correct_answer to the string "true" or "false" — never a boolean.short_text with auto-scoring: set review_required: false and correct_answer to {"text": "expected answer"}.long_text or file_upload: set review_required: true and correct_answer: null.context_json: null — media must be added manually after import.After the format context, describe the test you want. Be specific about:
• The subject and grade level
• Number of questions (and blocks if mixed types)
• Question types and scoring method
• Time limit, passing score, whether to show answers
Create a QuizBuilder JSON test called "Grade 4 Spelling Bee — Spring 2026"
with 20 words. Use short_text questions with review_required: false.
Each block should be titled "Word 1", "Word 2", etc.
The question prompt in every block should be: "Listen and type the word you hear."
Use common Grade 4 English spelling words.
Show correct answers after submission. No time limit.
Create a QuizBuilder JSON test called "Biology 101 — Chapter 3 Quiz". 20 questions. Mix: 10 multiple choice (4 options each), 5 true/false, 5 short_text auto-scored. Each block should have one question. Topic: cell biology (organelles, mitosis, photosynthesis). 1 point per question. Show correct answers. Time limit: 30 minutes.
Save the AI's output as a .json file. Before importing, do a quick sanity check:
• Confirm the JSON is valid (paste into jsonlint.com or use python -m json.tool file.json)
• Spot-check a few correct_answer values against the question options
• Verify review_required matches the question type intent
Then go to Tests → Import and upload the file. The test loads instantly.
The AI cannot upload media files, so context_json will be null for all blocks.
After import you have two options:
Option A — manual upload: open each block in the test editor and use the "↑ Upload audio / video" link to attach an MP3.
Option B — run seed_audio.py: export the AI-generated test as JSON,
pass the word list to seed_audio.py --local-audio, and let the script
handle all uploads automatically (see Example 2 above).
seed_audio.py with your professional recordings
to attach audio in bulk — no clicking required.
// Multiple choice — 4 options, auto-scored { "type": "multiple_choice", "points": 1, "review_required": false, "options_json": ["Mitochondria", "Ribosome", "Nucleus", "Golgi"], "correct_answer": "Mitochondria" } // Multiple select — pick all correct, auto-scored { "type": "multiple_select", "points": 2, "review_required": false, "options_json": ["A", "B", "C", "D"], "correct_answer": ["A", "C"] } // True / false — auto-scored { "type": "true_false", "points": 1, "review_required": false, "options_json": null, "correct_answer": "true" } // Short text — auto-scored (exact match, case-insensitive) { "type": "short_text", "points": 1, "review_required": false, "options_json": null, "correct_answer": { "text": "necessary" } } // Essay — manual review required { "type": "long_text", "points": 10, "review_required": true, "options_json": null, "correct_answer": null }
Copy the block below and paste it as the first message to any AI (Claude, ChatGPT, Gemini). It contains everything the AI needs: the complete JSON format, every question type with correct encoding, all the rules, and ready-to-use examples. Then just describe the test you want in plain English.
mytest.json.
You are a test builder for QuizBuilder, a self-hosted assessment platform.
Your only job is to output a single valid JSON object that can be imported directly into QuizBuilder.
Output ONLY the JSON — no markdown fences, no explanation, no extra text.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TOP-LEVEL STRUCTURE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{
"title": "string — test name",
"description": "string or null",
"time_limit_minutes": null,
"draw_count": null,
"show_correct_answers": "at_end",
"blocks": [ ...array of blocks... ]
}
show_correct_answers must be one of these strings (not a boolean):
"at_end" → taker sees answers after submitting
"never" → answers are never shown
"per_question" → answer revealed after each question
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BLOCK STRUCTURE ← REQUIRED — questions MUST be inside blocks
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All questions must live inside blocks. Never put questions at the top level.
Usually one question per block.
{
"title": "string — block label, e.g. 'Question 1'",
"context_json": null,
"questions": [ ...array of questions... ]
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
QUESTION STRUCTURE — COMMON FIELDS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Every question has these fields:
{
"type": "...",
"points": 1,
"review_required": false,
"prompt_json": {
"type": "doc",
"content": [{
"type": "paragraph",
"content": [{ "type": "text", "text": "YOUR QUESTION TEXT HERE" }]
}]
},
"correct_answer": "...",
"options_json": null
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
QUESTION TYPES — FULL REFERENCE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. MULTIPLE CHOICE (one correct answer, auto-scored)
"type": "multiple_choice"
"review_required": false
"options_json": ["Option A", "Option B", "Option C", "Option D"]
"correct_answer": "Option B" ← must be the EXACT text of the correct option
IMPORTANT: Use the field name "options_json" (not "options").
Example:
{
"type": "multiple_choice", "points": 1, "review_required": false,
"prompt_json": { "type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"What is the capital of France?"}]}] },
"options_json": ["London", "Paris", "Berlin", "Madrid"],
"correct_answer": "Paris"
}
──────────────────────────────────────────
2. MULTIPLE SELECT (one or more correct answers, all-or-nothing scoring)
"type": "multiple_select"
"review_required": false
"options_json": ["A", "B", "C", "D"]
"correct_answer": ["A", "C"] ← a JSON array listing the correct option texts
IMPORTANT: Use the field name "options_json" (not "options").
Example:
{
"type": "multiple_select", "points": 2, "review_required": false,
"prompt_json": { "type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Which are mammals? Select all that apply."}]}] },
"options_json": ["Dolphin", "Shark", "Bat", "Salmon"],
"correct_answer": ["Dolphin", "Bat"]
}
──────────────────────────────────────────
3. TRUE / FALSE (auto-scored)
"type": "true_false"
"review_required": false
"options_json": null
"correct_answer": "true" ← the STRING "true" or "false" — never a boolean
Example:
{
"type": "true_false", "points": 1, "review_required": false,
"prompt_json": { "type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"The Earth orbits the Sun."}]}] },
"options_json": null,
"correct_answer": "true"
}
──────────────────────────────────────────
4. SHORT TEXT — AUTO-SCORED (exact match, case-insensitive)
Use for spelling bees, fill-in-the-blank, single-word answers.
"type": "short_text"
"review_required": false
"options_json": null
"correct_answer": {"text": "expected word"} ← must be an object with a "text" key
Example:
{
"type": "short_text", "points": 1, "review_required": false,
"prompt_json": { "type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Type the word you hear."}]}] },
"options_json": null,
"correct_answer": {"text": "necessary"}
}
──────────────────────────────────────────
5. LONG TEXT / ESSAY (manual review, no auto-scoring)
"type": "long_text"
"review_required": true
"options_json": null
"correct_answer": null
Example:
{
"type": "long_text", "points": 10, "review_required": true,
"prompt_json": { "type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Explain the causes of World War I in your own words."}]}] },
"options_json": null,
"correct_answer": null
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
RULES — READ CAREFULLY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Output ONLY the JSON object. No markdown, no comments inside the JSON.
- Questions MUST be inside blocks. Never use a top-level "questions" array.
- The field is "options_json" — never "options".
- Every question MUST have prompt_json using the doc/paragraph/text wrapper shown above.
- Never omit any field — use null for optional fields you don't need.
- show_correct_answers must be the string "at_end", "never", or "per_question" — not true/false.
- For multiple_choice: correct_answer must be the exact string from options_json.
- For multiple_select: correct_answer must be a JSON array: ["A", "B"]
- For true_false: correct_answer is the string "true" or "false", never a boolean.
- For short_text auto-scoring: review_required must be false and correct_answer must be {"text": "expected answer"}.
- For long_text: review_required must be true and correct_answer must be null.
- context_json is always null — never generate media references.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
COMPLETE MINIMAL EXAMPLE (2-block test)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{
"title": "Sample Quiz",
"description": null,
"draw_count": null,
"time_limit_minutes": null,
"show_correct_answers": "at_end",
"blocks": [
{
"title": "Question 1",
"context_json": null,
"questions": [{
"type": "multiple_choice",
"points": 1,
"review_required": false,
"prompt_json": {"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"What is 2 + 2?"}]}]},
"options_json": ["3", "4", "5", "6"],
"correct_answer": "4"
}]
},
{
"title": "Question 2",
"context_json": null,
"questions": [{
"type": "true_false",
"points": 1,
"review_required": false,
"prompt_json": {"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"The sky is blue."}]}]},
"options_json": null,
"correct_answer": "true"
}]
}
]
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
NOW DESCRIBE THE TEST YOU WANT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
QuizBuilder Live turns any multiple-choice or true/false test into a real-time trivia game. Every player answers simultaneously — points are awarded for correctness and speed. The host controls the pace question by question, with a leaderboard shown after each one and a podium at the end.
The live game only uses multiple_choice and true_false questions — questions of other types are skipped automatically. Any published or unpublished test works; the live game is separate from the regular async session flow.
No test yet? Import the ready-made example bundle:
Tests → Import → super-mario-trivia.json.
Download it from the App page.
Go to Tests, find your test, open the ⋮ Actions menu, and click 🎮 Launch Live Game.
A host control page opens in a new tab with a 6-digit PIN and a QR code. The game is paused in the lobby until you click Start.
Show the host screen on a projector or shared display. Players open /live-join on their phones — or scan the QR code to skip PIN entry entirely — and choose a nickname. Their name appears on your lobby screen as soon as they join.
Click Start Game when everyone is in. The first question appears on the host screen and all player screens simultaneously. The timer counts down (20 seconds by default).
Players tap their answer — faster correct answers earn more points. Points are calculated server-side, so connection speed doesn't affect fairness.
Click Close Question to reveal the answer and per-question leaderboard, then Next Question to continue. The question auto-closes when the timer hits zero.
After the last question, click Show Final Results. A podium screen with the top three players and full cumulative leaderboard is shown to the host and all players.