Quick answer
Goodreads shut its developer API down in December 2020 and never brought it back — five years later, developers are still Googling for a replacement. Open Library, the Internet Archive's 30M+-work catalogue, has always had the equivalent fields (title, authors, ISBNs, subjects, cover art, edition count) sitting behind a free, keyless search.json endpoint. The gap isn't the data — it's the plumbing: pagination, rate-limit pacing, and normalizing a search API that was built for humans typing into a box, not pipelines pulling thousands of rows. The Open Library Books Scraper is that plumbing, returning 16 typed fields per work at $0.0015 per result plus a $0.005 run-start charge — $1.505 for 1,000 books.
Open Library's search API pages, but it doesn't tell you when to stop 📖
Open Library's /search.json endpoint doesn't return a total-count or a has_more flag — it just returns however many docs fit your limit for the page you asked for, capped at 100 per request. The only reliable stopping signal is inference: if a page comes back with fewer documents than you asked for, there's nothing left to page through. Get that boundary condition wrong — off by one, or missing the check entirely — and a bulk pull either loops past the end of the catalogue on requests that return nothing, or stops one page early and silently drops results near a query's tail. The scraper walks page upward, comparing each page's actual document count against the requested limit, and only advances while a full page came back.
edition_count is never null — even when Open Library doesn't send it 🔢
Some works genuinely have thin catalogue data, and Open Library's response for those omits edition_count outright rather than sending an explicit 0. A naive pass-through would surface that as null, which reads as "unknown" — a meaningfully different claim than "zero editions recorded." The row builder coerces a missing edition count to 0 explicitly (int(d.get("edition_count") or 0)), so a thin catalogue entry reports as a real zero, not an ambiguous gap.
The same discipline applies to cover art: cover_url_l is only ever constructed when Open Library's response includes a cover_i image ID. There's no guessing a cover URL from a title or ISBN — if the catalogue entry has no cover ID, the field is null, not a broken or placeholder image link.
Subjects are capped at 30, on purpose 🏷️
Some Open Library works carry hundreds of subject tags — crowdsourced, overlapping, occasionally redundant. Returning all of them would bloat every row with low-signal duplicates for a field most downstream use cases treat as a topical fingerprint, not an exhaustive taxonomy. subjects is truncated to the first 30 tags Open Library returns per work — enough for genre/topic classification and recommendation pipelines, without the tail of noise.
What we handle for you 🛡️
-
We rotate browser fingerprints —
curl-cffiimpersonation across Chrome, Firefox, and Safari TLS profiles. -
We retry with exponential backoff on
408 / 429 / 5xx, up to 5 attempts per page, honoringRetry-After. - We rotate residential proxies through Apify Proxy when enabled — fresh session and exit IP on every block.
- We pace against rate limits — when the catalogue API pushes back, we slow down instead of hammering into a ban.
- We keep the dataset clean — Pydantic-validated rows, explicit zero vs. null distinctions, ISO-8601 timestamps.
- You pay only for results that land. No data, no charge, beyond the small run-start fee.
Full output schema 📦
Sixteen fields per work:
| Field | Type | Notes |
|---|---|---|
openlibrary_key |
string | Open Library work key, e.g. /works/OL471576W
|
title |
string | Work title |
subtitle |
string | null | Subtitle, when present |
authors |
list[string] | Author names |
first_publish_year |
int | null | Earliest publication year recorded |
edition_count |
int | Coerced to 0 when Open Library omits the field — never null |
languages |
list[string] | Language codes across editions |
subjects |
list[string] | Subject tags, capped at 30 |
isbns |
list[string] | ISBN-10 and ISBN-13 detected |
publishers |
list[string] | Publishers across editions, deduped |
cover_id |
int | null | Open Library cover image ID |
cover_url_l |
string \ | null |
ratings_average |
float | null | Average rating, where Open Library has one |
ratings_count |
int | null | Rating count |
ebook_access |
string \ | null |
work_url |
string | Canonical Open Library URL |
scraped_at |
string | ISO-8601 row-creation timestamp |
Who this is for
Goodreads-API replacement — rebuild the bibliographic layer Goodreads took away in 2020: title, authors, ISBNs, subjects, cover URL, edition count.
Bulk ISBN lookup — enrich a CSV of book titles with ISBNs, authors, and cover art in one run, at better unit economics than a per-request ISBN API.
Recommendation and RAG pipelines — seed a book-rec backend or a fiction-RAG corpus with structured, CC0-licensed metadata.
Digital humanities — pull subject-tag corpora for distant-reading or cultural-analytics research at catalogue scale.
Frequently asked questions
Is this a Goodreads API replacement?
Yes, for the bibliographic-metadata layer — title, authors, ISBNs, subjects, cover URL, edition count. Goodreads shut its developer API in December 2020; Open Library carries the equivalent fields under a CC0 license, and this Actor is the bulk-export layer on top of it.
Why does edition_count show 0 instead of being missing?
Because Open Library's own response omits the field for thin catalogue entries rather than sending 0 — treating that as null would conflate "no data" with "genuinely zero editions." The row builder coerces the missing case to an explicit 0.
Why is subjects capped at 30 tags?
Some works carry hundreds of crowdsourced subject tags, most of them redundant for classification purposes. Thirty is enough signal for genre/topic pivots without the long noisy tail.
Can I get the full book text?
No — this Actor exports metadata only. Follow work_url to the Internet Archive reader for public-domain full text.
What does 5,000 results cost?
$7.505 — 5,000 × $0.0015, plus the $0.005 run-start charge.
Try it
Live on the Apify Store: Open Library Books Scraper.
Give it a title, author, ISBN, or subject query and get back typed, paginated rows across a 30M+-work catalogue. Pay-per-event, no subscription, no card required to try.
Built by Devil Scrapes — we build scrapers for the targets that fight back.
Top comments (0)