Skip to content

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.

  • Node.js 18+
  • TypeScript (we use tsx to run .ts files directly)
Terminal window
mkdir reading-quiz && cd reading-quiz
npm init -y
npm install studyplug

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.

quiz.ts
import { StudyPlug } from "studyplug";
import type { ContentItem } from "studyplug";
const sp = new StudyPlug();
// Generate items for a reading comprehension skill
const { data } = await sp.generate({
skill: "main-idea-details",
grade: "grade-4",
count: 6,
seed: 42,
});
console.log(`Loaded ${data.items.length} quiz items`);

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`);

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);
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}`);
}
Terminal window
npx tsx quiz.ts

Output:

Loaded 6 quiz items
Quiz has 6 questions
Quiz Results: 2/6
Score: 33%
Question 1: WRONG
Question 2: CORRECT
Question 3: WRONG
Question 4: CORRECT
Question 5: WRONG
Question 6: WRONG

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}`);
}
}

The same logic works in React, Vue, or any framework:

  1. Call sp.generate() on the server or in an API route
  2. Send questions to the client (without correctAnswer)
  3. Collect answers via form inputs
  4. Send answers back to the server for scoring
  5. Return the score and explanations

Keep correctAnswer server-side so students cannot inspect it in the browser.