Open Library & Gutenberg Book Lookup
Pricing
from $3.70 / 1,000 book records
Open Library & Gutenberg Book Lookup
Open Library Lookup that returns title, authors, publisher, subjects and cover art. 21 typed fields per book record. Add free full-text links from Project Gutenberg. Export to JSON, CSV or Excel, run it on a schedule, or call it from the Apify API.
Pricing
from $3.70 / 1,000 book records
Rating
0.0
(0)
Developer
angel nguyen
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
16 days ago
Last modified
Categories
Share
What this Actor does
Project Gutenberg and Open Library in one call: give this Actor a list of ISBNs and you get back clean book records — title, authors, publisher, subjects and cover — with free full-text links attached wherever the book is in the public domain. Neither source needs an account or an API key.

It also runs the other way round. Feed it titles or author names instead of ISBNs and it searches Open Library for matching editions, so a messy list of "book-ish strings" comes back as structured rows you can actually join on.
Key features
- Three ways in. ISBN-10 or ISBN-13 (hyphens and spaces are stripped), free-text titles, or author names.
- 21 fields per record, counted from a real run — title, subtitle, authors, both ISBNs, publishers, publish date, first publication year, page count, subjects, languages, cover URL and the Open Library key.
- Project Gutenberg join. Where a public-domain match exists, the record carries
gutenbergId,gutenbergFormats(the actual download links) andgutenbergDownloadCount— a real popularity signal, not an estimate. - A strict robots-clean mode.
gutenbergOnlyskips Open Library entirely and uses only Gutendex, whose robots.txt explicitly allows this. - Every row says how it was resolved.
queriedBy,queryandresolvedtravel with the record, so an unmatched input is visible rather than silently missing. - Deliberately unhurried. Concurrency defaults to 2 and is capped at 5, because this source throttles rather than scaling.
How it works
- You supply ISBNs, titles or authors, and choose whether to attach Project Gutenberg matches.
- ISBNs are normalised — hyphens and spaces stripped — and resolved against Open Library to exactly one edition each.
- Titles and authors go through Open Library search instead, returning up to
limiteditions per query. - If
includeGutenbergis on, each resolved book is looked up in Gutendex for a public-domain match, and any download formats found are attached. - If
gutenbergOnlyis on, steps 2 and 3 are skipped and Gutendex alone answers the query. - Each result is flattened to one typed row and pushed to the dataset, carrying the query that produced it.
An identifier that resolves to nothing still tells you so: the row records what was queried and that it did not resolve, rather than vanishing from the output.
Input
At least one of isbns, titles or authors must be non-empty.
Input fields
| Field | Type | Default | What it does |
|---|---|---|---|
isbns | array | ["9780261103283","9780141439518"] (prefilled) | ISBN-10 or ISBN-13. Hyphens and spaces are stripped. The most precise input — resolves to exactly one edition. |
titles | array | [] | Free-text title search against Open Library. |
authors | array | [] | Free-text author search against Open Library. |
includeGutenberg | boolean | true | Also query Gutendex for a public-domain match and attach download links plus download_count (a real popularity signal). Gutendex is the fully robots-clean source; leaving this on is recommended. |
gutenbergOnly | boolean | false | Skip Open Library entirely and use only Gutendex, whose robots.txt explicitly allows this. Open Library's robots.txt disallows /search and /api — see RESPONSIBLE-USE.md. Turning this on removes that flag at the cost of non-public-domain coverage. |
limit | integer | 10 | Max results per title/author query. Ignored for ISBN lookups, which return one edition each. |
language | string | "" | Optional ISO-639-2 code, e.g. 'eng'. Leave blank for no filter. |
maxConcurrency | integer | 2 | Kept low on purpose: a 30-request burst to Open Library measured 2x HTTP 429 and a connection reset, at a 1.76s median. Raising this will get you throttled, not served faster. |
Example input
Two real ISBN-13s — 9780261103283 is The Lord of the Rings, 9780553293357 is Foundation — with the Gutenberg join on.
{"isbns": ["9780261103283","9780553293357"],"includeGutenberg": true,"maxConcurrency": 2}
Output
One dataset item per resolved book. The record below is a real row from a real run of this Actor, copied unedited.
Example output
{"source": "openlibrary","title": "The hobbit","subtitle": "or There and back again","authors": ["J.R.R. Tolkien"],"isbn10": [],"isbn13": ["9780261103283"],"publishers": ["HarperCollins"],"publishDate": "2020","firstPublishYear": null,"numberOfPages": 300,"subjects": [],"languages": ["eng"],"coverUrl": "https://covers.openlibrary.org/b/id/149276-L.jpg","openLibraryKey": "/works/OL27482W","gutenbergId": null,"gutenbergDownloadCount": null,"gutenbergFormats": null,"queriedBy": "isbn","query": "9780261103283","resolved": true,"scrapedAt": "2026-08-22T07:33:40.342Z"}
Output fields
Every field below is taken from that same real record. Values are truncated for width, never invented.
| Field | Type | Value from a real run |
|---|---|---|
source | string | openlibrary |
title | string | The hobbit |
subtitle | string | or There and back again |
authors | array | ["J.R.R. Tolkien"] |
isbn10 | array | [] |
isbn13 | array | ["9780261103283"] |
publishers | array | ["HarperCollins"] |
publishDate | string | 2020 |
firstPublishYear | null | null |
numberOfPages | number | 300 |
subjects | array | [] |
languages | array | ["eng"] |
coverUrl | string | https://covers.openlibrary.org/b/id/149276-L.jpg |
openLibraryKey | string | /works/OL27482W |
gutenbergId | null | null |
gutenbergDownloadCount | null | null |
gutenbergFormats | null | null |
queriedBy | string | isbn |
query | string | 9780261103283 |
resolved | boolean | true |
scrapedAt | string | 2026-08-22T07:33:40.342Z |
The Gutenberg fields are populated only where a public-domain match exists — which is most of the pre-1929 canon and almost none of the modern catalogue. An empty gutenbergId means "no free full text found", not "lookup failed".
Pricing
Pay-per-event. You are charged per book record delivered; platform compute is not billed on top, and an identifier that resolves to nothing is never billed.
| Event | Price | Charged when |
|---|---|---|
| Book record | $0.004 | One resolved book: Open Library metadata plus the Project Gutenberg full-text join where one exists. |
| Actor start | $0.00001 | Starting a run is charged at the platform minimum of $0.00001 - effectively free. You pay for what the run actually delivers. An identifier we cannot resolve is never billed. |
What a run actually costs
Worked from the prices in the table above:
- A 500-ISBN backlist, resolved once. 500 records x $0.004 = $2.00, plus $0.00001 to start the run.
- A 20-book weekly refresh. 20 x $0.004 = $0.08 per run, about $0.35 a month.
- One ISBN. $0.00001 to start plus $0.004 for the record = $0.00401.
Unresolved identifiers cost nothing beyond the run start, so a dirty input list is cheap to discover.
FAQ
Do I need an API key for Open Library or Project Gutenberg?
No. Both are public, keyless sources. The Actor calls Open Library and Gutendex over plain HTTPS with no account and no token.
What is Gutendex?
Gutendex is the public JSON API over the Project Gutenberg catalogue. It is what the Actor queries for public-domain matches and download links, and its robots.txt explicitly allows this.
Why is maxConcurrency capped so low?
Because raising it does not make this faster. A 30-request burst against Open Library was measured returning two HTTP 429s and a connection reset, at a 1.76-second median. The default of 2 is the setting that actually finishes.
What does gutenbergOnly do, and why would I use it?
It skips Open Library entirely and answers from Gutendex alone. Open Library's robots.txt disallows /search and /api; gutenbergOnly removes that consideration completely, at the cost of losing every book that is not public domain.
Can I search by title instead of ISBN?
Yes — put strings in titles or authors. They run as free-text searches and return up to limit editions each. ISBNs remain the precise path: one ISBN resolves to exactly one edition.
Are the cover images included?
The record carries coverUrl, a link to the cover hosted by the source. The image bytes are not copied into your dataset.
Is the download count real?
Yes. gutenbergDownloadCount is Project Gutenberg's own published count for that book, passed through unchanged.
Limits and error handling
limitcaps results per title or author query at 100; it is ignored for ISBN lookups, which return one edition each.maxConcurrencyis capped at 5 and defaults to 2. This is a source-imposed ceiling, not caution: a 30-request burst measured 2 x HTTP 429 plus a connection reset.languagetakes an ISO-639-2 code such aseng; leave it blank for no filter.- An ISBN that matches no edition produces a row marked unresolved rather than disappearing.
- Books still in copyright will never carry Gutenberg fields — that is the licence, not a lookup failure.
Integrations and API
Everything below works on any Apify account, including the free tier.
Run it from the Apify API
Start a run and wait for the dataset in one call. Replace <YOUR_TOKEN> with your own Apify API token.
curl -X POST "https://api.apify.com/v2/acts/praise-most-high~book-isbn-catalog/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-H "Content-Type: application/json" \-d '{"isbns":["9780261103283","9780553293357"],"includeGutenberg":true,"maxConcurrency":2}'
Use it from JavaScript or Python
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_TOKEN>' });const run = await client.actor('praise-most-high/book-isbn-catalog').call({"isbns":["9780261103283","9780553293357"],"includeGutenberg":true,"maxConcurrency":2});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Schedules, webhooks and integrations
Run it on a schedule — hourly, daily, or a cron expression — and have the output pushed where you already work. Apify ships first-party integrations for Zapier, Make, n8n, Slack, Google Drive, GitHub and generic webhooks, and any run can fire a webhook on success or failure. The dataset is also readable directly as JSON, CSV, XLSX, XML or RSS from its own URL, so a spreadsheet or a BI tool can point straight at it.
Where the data comes from
Two public, keyless sources:
- Open Library — the Internet Archive's open bibliographic catalogue. Supplies title, authors, publishers, dates, page counts, subjects, languages and cover URLs.
- Project Gutenberg, via the Gutendex API — supplies the public-domain full-text match, its download formats, and Project Gutenberg's own download count.
Both are read live over plain HTTPS on every run. No account, no API key, no session cookie, no headless browser and no proxy rotation. Open Library's robots.txt disallows /search and /api, which is why gutenbergOnly exists as a strict mode for users who want to stay entirely inside a source that allows this explicitly.
Legal and responsible use
Unofficial. This Actor is not affiliated with, endorsed by, or sponsored by the Internet Archive, Open Library or Project Gutenberg. Their names are used only to describe the public data sources it reads.
No personal data. Bibliographic metadata about published works only — no borrower records, no reader accounts, no reviews.
Your obligations. Public-domain status is per-work and per-jurisdiction. Project Gutenberg texts are public domain in the United States; that does not automatically hold where you are. Open Library metadata carries its own terms. Check before you republish.
Support and feedback
Found a bug, a wrong field, or a source that changed shape? Open an issue on the Issues tab of this Actor and it goes straight to the maintainer. Feature requests are welcome on the same tab. If a run failed, include the run ID — the log is what makes it fixable.