Issue Nº 18 — Sep 4, 2026
Openverse's anonymous search stops at 240 results, and paging past it returns a 401
Issue eighteen covers Openverse, a search engine for openly licensed and public domain images and audio. It grew out of the old Creative Commons catalog. This session queried it live, with no key and no sign-up. It found a hard 240-result cap on anonymous search, rate-limit headers that barely move, and per-source counts putting the image catalogue past 915 million works.
What it covers
Openverse searches openly licensed and public domain media: images through GET /v1/images/, audio through GET /v1/audio/. The catalog moved here after Creative Commons handed it to WordPress.org. The old api.creativecommons.engineering host now redirects to api.openverse.org.
A live GET to /v1/images/?q=cat&page_size=2 this session returned a 200 with 2,793 bytes of JSON, no key required. A live GET to /v1/audio/?q=jazz&page_size=2 returned the same shape: result_count, page_count, page_size, page, and results. Both hero endpoints work anonymously.
An OPTIONS preflight against /v1/images/, sent with an Origin header of https://greatapis.com, returned 200. access-control-allow-methods listed DELETE, GET, OPTIONS, PATCH, POST, and PUT, matching the cors: yes on file.
A 240-result ceiling, and a 401 if you page past it
Every query with enough matches reports a result_count that tops out at 240, no matter how common the term. Live GETs for q=cat, q=nature, q=landscape, q=city, and q=dog each returned exactly 240, with page_count scaling to match the page_size sent.
Paging past that ceiling does not just return an empty page. GET /v1/images/?q=cat&page_size=20&page=13 returned 401 Unauthorized with the body {"detail":"pagination depth may not exceed 240 for anonymous requests"}. Page size is capped too: GET /v1/images/?q=cat&page_size=500 returned the same 401 status, this time with {"detail":"page_size may not exceed 20 for anonymous requests"}.
The 401 status is misleading. Nothing is wrong with the request's credentials; it just asked for more than an anonymous caller may have. Both limits are intentional: the API's own schema, at /v1/schema/, says pagination is restricted for anonymous users so the catalog can't be scraped, per Openverse's terms of service.
The rate-limit headers barely move
Every response carries x-ratelimit-limit-anon_burst: 20/min and x-ratelimit-limit-anon_sustained: 200/day, plus available counters for both. This session made about 30 calls inside a few minutes. The burst-available counter read 19 on nearly all of them, dropped to 18 once, then climbed back to 19 on the very next call.
The sustained-available counter held at 199 through the first eight calls, dropped to 198 once, and did not move again for the rest of the session, even as more calls went out. These headers are not an exact remaining count. A client that reads them to decide when to back off should treat them as approximate.
GET /v1/rate_limit/, the endpoint the schema lists for checking your own usage, returned 401 with {"detail":"Authentication credentials were not provided."} Anonymous callers can't check it at all; they're left with the approximate headers on every other response.
Signing up for a token still behaves as documented. POST /v1/auth_tokens/register/ with an empty body returned 400, listing name, description, and email as required fields, not a 404.
915 million images, three sources for audio
GET /v1/images/stats/ returned 200 with 52 rows, one per source, each carrying a media_count. Summed, they total 915,519,784 images. Flickr alone accounts for 536,219,600 of that, more than half. iNaturalist follows at 266,268,617, then Wikimedia Commons at 88,962,441.
GET /v1/audio/stats/ lists only three sources: Wikimedia Commons audio at 3,950,590 works, Jamendo at 644,742, and Freesound at 591,450, a combined 5,186,782. Audio is a small fraction of what Openverse indexes.
The bundled OpenAPI document at /v1/schema/ still lists the same 17 path templates as the checked-in spec file, so the entry's specFile needs no update. A bad license filter is also rejected cleanly: GET /v1/images/?q=cat&license=notalicense returned 400 with {"detail":{"license":["License 'notalicense' does not exist."]}}.
Creative Commons Catalog, by the numbers
20 requests/min burst + 200 requests/day sustained for anonymous requests, confirmed live via the x-ratelimit-limit-anon_burst / x-ratelimit-limit-anon_sustained response headers
- GET/v1/images/
- GET/v1/audio/