Web Data Labs › Blog › Useless Facts Scraper

How to Get Random Fun Facts Programmatically (Useless Facts API Guide)

May 3, 2026  ·  5 min read

Random trivia is one of those weird primitives that ends up in more software than you would expect. Daily newsletters that open with a curious fact to lift the rest of the email. Trivia apps that need an endless supply of fresh material so the same player does not see the same card twice in a week. Discord and Slack bots that drop a fact-of-the-day at 9am to nudge a quiet channel back to life. Chatbots that fall back to a friendly aside when the user asks something they cannot answer. Educational platforms that intersperse facts between lessons to keep attention. None of these products are about trivia, but every one of them needs a steady supply of short, well-formed, original facts on tap.

This post walks through why programmatic fun-fact data is its own surprisingly fiddly little problem domain, what a clean fact feed actually looks like, and what the record shape and request patterns should be for random facts, fact-of-the-day, and lookups by ID.

Why programmatic trivia matters

What makes fact data access fiddly

The Useless Facts API is a generous public good, but building production fact features directly on top of any third-party feed has a familiar set of failure modes. The endpoint can be rate-limited, the JSON shape can shift over time, the source domain can move, and the language coverage can change. Beyond plain availability, the consumer side has its own quirks: facts contain quotation marks and special characters that need careful escaping, repeated random calls can return the same fact twice in a row, and the fact-of-the-day endpoint changes once per UTC day — not once per local day — which surprises users in distant timezones.

Random does not mean uniform: A naive integration that fires “give me one random fact” on every page load will, sooner or later, hand the same fact to the same user twice in a session. A production trivia feature wants either a batch-and-shuffle pattern, a per-user seen-set with deduplication, or both. The data layer is one decision; the “do not show this user the same fact twice” layer is a separate one and worth thinking about up front.

What a normalised fact record looks like

Whichever endpoint a fact came from, normalise it to one compact shape so downstream code never has to branch on its origin:

{
  "id": "5f048654915ace42c3ab2c246fdc2457",
  "text": "US gold coins used to say “In Gold We Trust”.",
  "source": "djtech.net",
  "source_url": "https://www.djtech.net/humor/shorty_useless_facts.htm",
  "language": "en",
  "permalink": "https://uselessfacts.jsph.pl/api/v2/facts/5f048654915ace42c3ab2c246fdc2457",
  "scraped_at": "2026-05-03T12:39:29.238Z"
}

Keep the id and the permalink even if you never display them — the id is what your per-user seen-set is keyed on, and the permalink is how you re-fetch a curated fact later without storing its text as the only copy. Keep language too, because caching a German fact under an English key is the bug you will otherwise ship.

The four shapes of request worth supporting

Whatever you build on, a fact feature only ever asks for four things, and building your data layer around exactly these keeps it small:

ActionWhat you getInputs that matter
randomN random factscount, language
todayThe fact of the day (changes once per UTC day)language
byIdOne specific fact by IDid, language
batchMultiple specific facts by IDids, language

The batch case is the one people leave out and then need: it is how you re-fetch a curated set after an editor picks favourites, and how you rehydrate a cache without a hundred single calls.

Wiring it into a daily newsletter or bot

The natural pattern is a small scheduled job — a cron, a serverless function, or a daily Apify run — that requests one fact (or a small batch), stores it in your own database keyed by date, and renders it from there. You get caching, replay, and editorial override for free, and the third-party API only sees one call per day per surface instead of one call per page view. For chatbots and Discord/Slack integrations, fetching a small batch of 50 facts in the morning and serving them locally over the rest of the day is almost always the right shape: it stays well inside everyone’s rate limits and keeps response time inside the bot loop fast.

Building the plumbing yourself

If you wire this up directly, the part that gets people in trouble is not the first request — it is everything around it. Rate limits, retries on transient failures, IP rotation when a single endpoint pushes back, language-aware caching, deduplication for “random” results, and consistent UTF-8 handling for non-ASCII characters in fact text. For anything where the data layer is incidental to the actual product (a newsletter, a bot, an app), a proxy provider like Oxylabs handles the “do not get blocked” layer, and a managed scraper handles the “do not babysit a scraper at 3am” layer.