Build a Quiz
This tutorial builds a simple digital quiz that generates mixed-format questions from the StudyPlug API, collects answers, and scores them. Everything is in TypeScript and runs in Node.js — you can adapt the logic for any frontend framework.
Prerequisites
Section titled “Prerequisites”- Node.js 18+
- TypeScript (we use
tsxto run.tsfiles directly)
1. Install the SDK
Section titled “1. Install the SDK”mkdir reading-quiz && cd reading-quiznpm init -ynpm install studyplug2. Generate Mixed Content
Section titled “2. Generate Mixed Content”We will generate multiple-choice and true-false items for a reading skill. The API returns structured ContentItems that include everything you need to render questions and check answers.
import { StudyPlug } from "studyplug";import type { ContentItem } from "studyplug";
const sp = new StudyPlug();
// Generate items for a reading comprehension skillconst { data } = await sp.generate({ skill: "main-idea-details", grade: "grade-4", count: 6, seed: 42,});
console.log(`Loaded ${data.items.length} quiz items`);3. Build a Quiz Data Structure
Section titled “3. Build a Quiz Data Structure”Transform the raw ContentItems into a quiz-friendly format. Each question gets an id, the display text, the choices (if applicable), and the correct answer stored separately for scoring.
interface QuizQuestion { id: string; number: number; text: string; type: "multiple-choice" | "true-false"; choices?: string[]; correctAnswer: string | number | boolean;}
function toQuizQuestion(item: ContentItem, index: number): QuizQuestion | null { const base = { id: item.id, number: index + 1 };
if (item.content.type === "multiple-choice") { return { ...base, type: "multiple-choice", text: item.content.stem, choices: item.content.choices.map((c) => c.text), correctAnswer: item.content.correctIndex, }; }
if (item.content.type === "true-false") { return { ...base, type: "true-false", text: item.content.statement, correctAnswer: item.content.isTrue, }; }
return null; // Skip unsupported types}
const questions = data.items .map((item, i) => toQuizQuestion(item, i)) .filter((q): q is QuizQuestion => q !== null);
console.log(`Quiz has ${questions.length} questions`);4. Score the Quiz
Section titled “4. Score the Quiz”In a real app, you would collect user input from a form. Here we simulate student answers and score them against the correct values.
// Simulated student answers (index for MC, boolean for T/F)const studentAnswers: Record<string, string | number | boolean> = { [questions[0]?.id]: 2, // multiple-choice index guess [questions[1]?.id]: 0, // multiple-choice index guess [questions[2]?.id]: true, // true-false guess [questions[3]?.id]: 1, // multiple-choice index guess [questions[4]?.id]: false, // true-false guess [questions[5]?.id]: 3, // multiple-choice index guess};
function scoreQuiz( questions: QuizQuestion[], answers: Record<string, string | number | boolean>,): { correct: number; total: number; results: { question: number; correct: boolean }[] } { const results = questions.map((q) => { const studentAnswer = answers[q.id]; const isCorrect = studentAnswer === q.correctAnswer; return { question: q.number, correct: isCorrect }; });
return { correct: results.filter((r) => r.correct).length, total: results.length, results, };}
const score = scoreQuiz(questions, studentAnswers);5. Show Results
Section titled “5. Show Results”console.log(`\nQuiz Results: ${score.correct}/${score.total}`);console.log(`Score: ${Math.round((score.correct / score.total) * 100)}%\n`);
for (const r of score.results) { const mark = r.correct ? "CORRECT" : "WRONG"; console.log(` Question ${r.question}: ${mark}`);}Run the Complete Quiz
Section titled “Run the Complete Quiz”npx tsx quiz.tsOutput:
Loaded 6 quiz itemsQuiz has 6 questions
Quiz Results: 2/6Score: 33%
Question 1: WRONG Question 2: CORRECT Question 3: WRONG Question 4: CORRECT Question 5: WRONG Question 6: WRONGUsing the Answer Key Instead
Section titled “Using the Answer Key Instead”The data.answerKey array provides a parallel way to check answers. Each entry has itemId, answer (display string), and an optional explanation. This is useful for showing feedback after the quiz:
for (const entry of data.answerKey) { console.log(`Item ${entry.itemId}: ${entry.answer}`); if (entry.explanation) { console.log(` Why: ${entry.explanation}`); }}Adapting for a Frontend
Section titled “Adapting for a Frontend”The same logic works in React, Vue, or any framework:
- Call
sp.generate()on the server or in an API route - Send
questionsto the client (withoutcorrectAnswer) - Collect answers via form inputs
- Send answers back to the server for scoring
- Return the score and explanations
Keep correctAnswer server-side so students cannot inspect it in the browser.
Next Steps
Section titled “Next Steps”- Build a Worksheet — generate printable content instead
- Content Types — see all 12 content body types and their fields
- Error Handling — handle rate limits and API errors gracefully
- SDK Reference — full SDK documentation