quizbase
Skip to content
Command Palette
Search for a command to run...
QuizBase · Docs
by Maciej Dzierżek · published May 15, 2026 · 15 min read · Beginner
moodle-canvas-lms-module hero illustration
Illustration for: Embed QuizBase trivia in Moodle and Canvas LMS · Generated with Nano Banana, brand style

Embed QuizBase trivia in Moodle and Canvas LMS#

Moodle and Canvas both let you paste raw HTML into a Page activity. That’s all the surface area you need to drop in a working five-question trivia activity that pulls from QuizBase, runs on the student’s device, and reports the score back to the student (or, in a paid Canvas tier, back to the gradebook). No plugin install, no admin permission, no LTI integration headache.

This guide gives you a single <script>+<div> snippet you paste into a Moodle Page or Canvas Page editor. Five questions, four-choice each, score reveal at the end, attribution rendered on every card. About 60 lines of self-contained HTML.

What you’ll build#

A self-contained HTML widget that:

  • Renders inside a Moodle Page or Canvas Page — works in both editors
  • Fetches 5 questions from QuizBase on load (one round, no pagination)
  • Shows one question at a time with 4 shuffled answer choices
  • Tracks correct/incorrect locally in browser memory (resets on page refresh)
  • Shows final score at the end + “try again” button
  • Renders attribution on every question card — license compliance baked in
  • Configurable category and difficulty via inline HTML data attributes

The mechanic — single-page batch fetch with stable IDs#

Five questions fetched in one paginated call via /api/v1/questions. We use ?limit=5 and pass category + lang as query params. Each question has a stable id we don’t need — the student doesn’t replay individual cards, the quiz is one-shot. But the IDs make it possible to add features later (skip-this-one-later, report-wrong, link from gradebook). See /docs/api/questions-by-id for the stable-ID pattern catalogue.

Stack#

  • A QuizBase publishable keyqb_pk_*, free tier. Note: the key is visible to the student in this embed model (it’s in the inline <script>). For a public-school Moodle that’s fine — publishable keys are read-only and the free tier doesn’t bill on usage. For internal-only Canvas, see “Pitfalls” below.
  • A Moodle or Canvas instance where you can create Page activities — every standard install supports this.

Step 1 — Get a QuizBase publishable key#

Create a qb_pk_* key. Publishable is the right kind here — read-only API access, safe to embed in HTML the student can View Source on. Free tier 500 req/day = ~100 classes of 30 students taking the same quiz; for bigger schools or repeat usage, upgrade.

Sign up if you don’t have an account — no credit card, full production data on free tier.

Step 2 — Build the embed snippet#

The whole widget is 60 lines of HTML + inline JS. Save this to a text file, replace YOUR_KEY and CATEGORY:

<div id="quizbase-widget" data-category="science-and-nature" data-difficulty="medium" data-lang="en">
	<p>Loading...</p>
</div>

<script>
	(async function () {
		const KEY = 'YOUR_PUBLISHABLE_KEY'; // qb_pk_*
		const el = document.getElementById('quizbase-widget');
		const cat = el.dataset.category;
		const diff = el.dataset.difficulty;
		const lang = el.dataset.lang;

		const url = `https://quizbase.runriva.com/api/v1/questions/random?category=${cat}&difficulty=${diff}&lang=${lang}&amount=5`;
		const r = await fetch(url, { headers: { 'X-API-Key': KEY } });
		const { data: questions } = await r.json();

		let index = 0;
		let score = 0;

		function shuffle(a) {
			for (let i = a.length - 1; i > 0; i--) {
				const j = Math.floor(Math.random() * (i + 1));
				[a[i], a[j]] = [a[j], a[i]];
			}
			return a;
		}

		function render() {
			if (index >= questions.length) {
				el.innerHTML = `<h3>Score: ${score} / ${questions.length}</h3>
					<button onclick="location.reload()">Try again</button>`;
				return;
			}
			const q = questions[index];
			const choices = shuffle([q.correctAnswer, ...q.incorrectAnswers]);
			el.innerHTML = `<h3>Q${index + 1}: ${q.text}</h3>
				<div>${choices.map((c, i) => `<button onclick="window.__pick('${c.replace(/'/g, "\'")}')">${'ABCD'[i]}. ${c}</button>`).join('<br>')}</div>
				<small>Source: ${q.attribution.author} (${q.attribution.license})</small>`;
		}

		window.__pick = function (choice) {
			const q = questions[index];
			if (choice === q.correctAnswer) score++;
			index++;
			render();
		};

		render();
	})();
</script>

<img
  src="/docs/guides/moodle-canvas-lms-module-hero.webp"
  alt="moodle-canvas-lms-module hero illustration"
  class="my-6 aspect-video w-full rounded-2xl object-cover shadow-sm"
  loading="lazy"
/>

<style>
	#quizbase-widget button {
		display: block;
		margin: 4px 0;
		padding: 8px 12px;
		text-align: left;
		min-width: 240px;
	}
	#quizbase-widget small {
		display: block;
		margin-top: 12px;
		color: #888;
		font-size: 12px;
	}
</style>

The <small> attribution at the bottom of each question card is required. QuizBase questions ship under CC BY-SA / CC BY / MIT, and surfacing source on every card is a license requirement. See /data for the full attribution rules.

Step 3 — Paste into Moodle Page#

In your Moodle course: Add an activity or resource → Page. Give it a title, then in the Page content editor switch to the HTML source view (the </> icon in the toolbar). Paste the entire snippet from Step 2. Save. Students opening the page now see a working quiz.

To change category, edit the HTML and update the data-category attribute — slug values come from /api/v1/categories (science-and-nature, general-knowledge, history, etc.).

Step 4 — Paste into Canvas Page#

Canvas: Pages → New Page. Give it a title. In the rich editor click the </> icon (HTML editor toggle). Paste the snippet. Save. Same result — students see a working quiz when they open the page.

Canvas allows iframe embed too if your school has stricter HTML sanitization. In that case host the snippet on a public URL (GitHub Pages, Netlify, your school’s WordPress) and embed via <iframe src="..."> — Canvas allows iframes from the same domain plus a school-managed allow list.

Step 5 — Optional: category/difficulty picker for teachers#

Make the quiz reusable across classes — add a small <select> at the top so teachers pick category/difficulty without re-editing HTML each time:

<div id="quizbase-controls">
	Category:
	<select id="cat">
		<option value="science-and-nature">Science</option>
		<option value="history">History</option>
		<option value="geography">Geography</option>
		<option value="animals">Animals</option>
	</select>
	Difficulty:
	<select id="diff">
		<option value="easy">Easy</option>
		<option value="medium" selected>Medium</option>
		<option value="hard">Hard</option>
	</select>
	<button onclick="window.__startQuiz()">Start</button>
</div>
<div id="quizbase-widget"></div>

Wrap your existing fetch logic in window.__startQuiz = async () => { ... } and read selections from the dropdowns. Teachers now reuse the same Page across units without editing HTML.

Pitfalls#

  • The publishable key is visible to students — they can View Source. For public-school Moodle this is fine (the key is read-only, free tier caps at 500 req/day). For internal-corporate or paid Canvas where the key value matters, proxy fetches through a tiny /api/quizbase endpoint on your school’s server.
  • Iframe embeds may have CORS issues — QuizBase REST has CORS open for GET requests. If you see CORS errors in DevTools, you’re calling from a Page that’s been sanitized into an iframe — check the iframe’s src domain.
  • Moodle filters can strip <script> — older Moodle 3.x sites had aggressive HTML cleaners. If your <script> tag disappears after save, ask your admin to enable the “Format HTML allows JavaScript” filter or upgrade to Moodle 4.0+.
  • Free tier rate limit shared across all students hitting the page in the same hour — 30 students × 5 questions × 6 classes/day = 900 req/day, above 500 free. Bigger schools should upgrade or proxy through cached responses.

What next#

  • Multilingual Moodle pages — duplicate the Page per language, change the data-lang attribute. See languages and translations for the EN/PL/ES/FR matrix.
  • Anki shared-deck export — same content, different format. See Anki flashcards generator.
  • LTI 1.3 gradebook sync — the big-school path. Requires hosting your own LTI provider (Moodle and Canvas both support 1.3). QuizBase as the question backend is unchanged.
  • Bell-ringer warm-up variant — single-question card at the start of class. Replace ?limit=5 with ?limit=1, drop the score reveal, link from your Moodle course front page.

Ready to embed? Grab a free publishable key (no card, 500 req/day), paste the snippet into a Moodle or Canvas Page, ship to your class today. Bug in a question? Use POST /api/v1/report — or just edit the Page to skip it.