Blog

How to get free trivia questions from an API

Will Fry4 min read

If you're building a quiz app, a game for your Discord server or something for the next pub quiz, the code is usually the easy bit. Finding enough good questions is a lot harder.

That's what The Trivia API is for. One request gets you a batch of random multiple choice questions as JSON. It's free for non-commercial projects, and you don't need to sign up or get an API key to start.

This post is basically everything you need to get going: making a request, filtering the questions you get back, and using them from JavaScript, TypeScript or Python.

Your first request

Everything starts at /v2/questions. Paste this into a terminal:

curl "https://the-trivia-api.com/v2/questions?limit=1"

You get back an array of questions:

[
  {
    "id": "65056fd57a97013de78b54d1",
    "category": "science",
    "difficulty": "easy",
    "question": { "text": "What best describes the pH of lemon juice?" },
    "correctAnswer": "Acidic",
    "incorrectAnswers": ["Neutral", "Basic", "Sterile"],
    "tags": ["science"],
    "type": "text_choice",
    "regions": [],
    "isNiche": false
  }
]

Each one has the question text, the correct answer and three incorrect ones. It also has a category, difficulty and tags, which you can filter on (more on that next).

Picking the questions you want

By default you get 10 questions from any category, at any difficulty. Query parameters narrow that down, and you can mix and match them:

ParameterWhat it doesExample
limitHow many questions you get. Defaults to 10.limit=20
categoriesOnly questions from these categoriescategories=science,history
difficultiesOnly easy, medium or hard questionsdifficulties=easy,medium
tagsOnly questions about these more specific topicstags=dinosaurs,space

Multiple values are comma separated. The categories are music, sport_and_leisure, film_and_tv, arts_and_literature, history, society_and_culture, science, geography, food_and_drink and general_knowledge.

Tags are where it gets more specific. There are over 1,500 of them, from football to the_beatles (the tags endpoint has the full list).

So five hard geography questions looks like this:

curl "https://the-trivia-api.com/v2/questions?limit=5&categories=geography&difficulties=hard"

JavaScript

Plain fetch is all you need, and it works in the browser and in Node 18+. URLSearchParams saves you from gluing the query string together yourself:

const params = new URLSearchParams({
  limit: "10",
  categories: "science,history",
  difficulties: "easy",
});
 
const response = await fetch(`https://the-trivia-api.com/v2/questions?${params}`);
if (!response.ok) {
  throw new Error(`The Trivia API responded with ${response.status}`);
}
 
const questions = await response.json();
 
for (const question of questions) {
  console.log(question.question.text);
}

Shuffling the answers

The correct answer comes back separately from the incorrect ones, so you'll want to mix them up before showing them to anyone. A Fisher-Yates shuffle is the way to do it:

const shuffle = (items) => {
  const shuffled = [...items];
  for (let i = shuffled.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
  }
  return shuffled;
};
 
const answers = shuffle([question.correctAnswer, ...question.incorrectAnswers]);

You'll probably see answers.sort(() => Math.random() - 0.5) suggested a lot. I'd avoid it: it's biased, so the correct answer turns up in some positions more often than others. Your more competitive players will notice.

TypeScript

If you're using TypeScript, there's an SDK: @trivia-api/sdk. It has typed functions for every endpoint, no dependencies, and it works anywhere fetch does.

npm install @trivia-api/sdk

import { getRandomQuestions } from "@trivia-api/sdk";
 
const questions = await getRandomQuestions({
  limit: 10,
  categories: "science,history",
  difficulties: "easy",
});
 
for (const question of questions) {
  // The type field tells TypeScript which kind of question this is
  if (question.type === "text_choice") {
    console.log(question.question.text, question.correctAnswer);
  }
}

If a request fails it throws an ApiError with the status code on it, so it's easy to tell a rate limit (429) apart from your wifi dropping out.

Python

Same thing with requests:

import requests
 
response = requests.get(
    "https://the-trivia-api.com/v2/questions",
    params={"limit": 10, "categories": "science,history", "difficulties": "easy"},
    timeout=10,
)
response.raise_for_status()
 
for question in response.json():
    print(question["question"]["text"])
    print("Answer:", question["correctAnswer"])

Limits (and when you need a key)

Without a key you can get up to 50 questions per request. Ask for more and you'll just get 50. There's also a rate limit of 20 requests every 5 seconds per IP address, and anything over that gets a 429.

In practice that's plenty, as long as you fetch a whole quiz's worth of questions up front rather than one at a time.

If you're using it commercially you'll need a subscription. That also gets you:

  • bigger batches
  • sessions, so players never see the same question twice
  • image questions
  • questions in other languages

What next

The docs have every endpoint and parameter, with example responses.

Build with The Trivia API

The docs cover every endpoint, parameter and response. No API key is needed to get started.

License

Information about the Creative Commons license for The Trivia API.

The API and all data returned from it are licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

Creative Commons License

This means that the API and the questions it returns are free for noncommercial use. If you have somewhere suitable in your app, then please credit the API somewhere discreet — we love having our hard work shared!

If you would like to use the API commercially, or would like enhanced functionality, this service is offered through a paid subscription.

Sign in

Sign in to access your API key and manage your account.

or continue with email