Goodreads Book Scraper — Author Bibliography & Series avatar

Goodreads Book Scraper — Author Bibliography & Series

Under maintenance

Pricing

from $4.99 / 1,000 results

Go to Apify Store
Goodreads Book Scraper — Author Bibliography & Series

Goodreads Book Scraper — Author Bibliography & Series

Under maintenance

Goodreads Book Scraper: Extract book titles, authors, ratings, reviews, publication dates, genres, series details, and author bibliographies. Discover complete reading lists, series order, related books, and structured data for book research and literary analysis.

Pricing

from $4.99 / 1,000 results

Rating

0.0

(0)

Developer

API Empire

API Empire

Maintained by Community

Actor stats

0

Bookmarked

6

Total users

0

Monthly active users

a day ago

Last modified

Share

Goodreads Book Scraper — Books, Author Bios & Series as JSON

Goodreads Book Scraper expands a Goodreads author into their full bibliography, or a keyword into a list of books, and returns typed JSON — no HTML, no selectors. Every book row carries ratings, publication data, the author profile (bio, followers, total works) and series placement, and every author target closes with one summary row rolling up titles collected, average rating, and best/worst rated title. Read on for the exact input parameters, every output field, and how the retry and enrichment logic behave.

What is Goodreads Book Scraper?

Goodreads Book Scraper is an Apify Actor that turns a Goodreads author name, author link, or plain book search term into structured book data. It reads Goodreads' own listing pages and public book-data endpoint directly — no Goodreads account or login is required. Two lanes run independently in the same job: an author lane that walks an author's published titles and adds one rollup row per author, and a keyword lane that returns plain search results.

  • Expand an author into their full bibliography
  • Enrich every title with the author's profile (bio, followers, total works)
  • Mark each title's series and its placement inside that series
  • Close each author with one summary row (average rating, top/lowest/most-rated title, publication span, series covered)
  • Run plain keyword or search-URL lookups in the same job
  • Export as JSON, CSV, Excel or XML, or pull results straight from the Apify API

What data does Goodreads Book Scraper collect?

Every run can return up to four kinds of rows, depending on which lanes and toggles are used.

Data TypeKey FieldsJSON Field Names
Bookstitle, listed author, rating, ratings count, published year, editions, cover, URLtitle, author, rating, ratingValue, ratingsCount, ratingsCountValue, published, publishedYear, editions, url, coverUrl, bookId
Author profile (per book)resolved author name, id, page URL, photo, bio, followers, total works, contributor roleauthorId, authorName, authorUrl, authorProfileImageUrl, authorBio, authorFollowersCount, authorWorksCount, authorRole, contributors
Series placement (per book)is it part of a series, series title, URL, placement number, how many series it's in, full series listisPartOfSeries, seriesTitle, seriesUrl, seriesPlacement, seriesCount, allSeries
Author summary (one per author target)titles collected, average rating, total ratings, top/lowest/most-rated title, publication span, series coveredbooksCollected, avgRatingOfCollectedBooks, totalRatingsOfCollectedBooks, topRatedTitle, topRatedRating, lowestRatedTitle, lowestRatedRating, mostRatedTitle, mostRatedRatingsCount, earliestPublishedYear, latestPublishedYear, distinctSeriesCount, seriesTitles

How does Goodreads Book Scraper differ from the official Goodreads API?

Why not build this yourself? Goodreads is not a realistic target for a "just call the official API" approach. Goodreads stopped issuing new developer API keys on December 8, 2020 and has not reopened public developer access since — so there is no current official API a new integration can register for.

Building a replacement yourself means maintaining an HTML parser against a page Goodreads can restyle at any time, handling the listing-page interstitials Goodreads serves on some requests instead of the real results, running your own proxy pool to avoid IP blocks, and separately reverse-engineering the book-data endpoint used for author and series enrichment. Goodreads Book Scraper already does all four: it retries an interstitial instead of accepting it as "no more results," rotates through Apify Proxy on failure, and ships with the enrichment endpoint wired in.

If you only need one or two books, reading the page by hand is faster. For a repeatable pipeline — an author catalog, a series index, or a scheduled book-discovery feed — a maintained scraper removes the parsing and retry logic you would otherwise own.

Why do developers and teams scrape Goodreads?

For AI engineers and agent builders

Author bibliographies with a stable JSON shape are a clean source for RAG indexing or recommendation-agent tooling: pass authorTargets for a set of authors, and each returned book row already carries title, ratingValue, publishedYear, and seriesTitle for grounding an agent's answers about an author's body of work, without writing an HTML parser into the agent's tool loop.

For researchers and analysts

Rating and publication-year fields (ratingValue, ratingsCountValue, earliestPublishedYear, latestPublishedYear) support publication-trend or reception studies across an author's career, using only data Goodreads already publishes on public pages — no login, no private data.

For developers building data products

The author summary row (booksCollected, avgRatingOfCollectedBooks, distinctSeriesCount) is a ready-made rollup for a book-discovery feed or an author-comparison dashboard, so the aggregation doesn't have to be recomputed downstream from raw book rows.

For publishing and content teams

Series placement (isPartOfSeries, seriesPlacement, allSeries) makes it possible to reconstruct reading order for a series or check whether a backlist title has been correctly credited to its author on Goodreads.

How to scrape Goodreads (step by step)

  1. Open Goodreads Book Scraper on its Apify Store page and click Try for free (or Run, if you already have it saved).
  2. Provide at least one input: an author in authorTargets (name, author link, or bare author id) or a term in bookSearchTerms. The run raises an error if both are left empty.
  3. Set booksPerAuthor / resultsPerSearch to cap how many titles come back per target, and toggle includeAuthorProfile and includeSeriesInfo for the columns you want.
  4. Click Start and watch the run log — it reports each author resolved and each page collected.
  5. Download the dataset as JSON, CSV, Excel or XML from the Storage tab, or pull it with the Apify API / apify-client.

What to do when Goodreads changes its structure

The Actor is maintained, and the output schema is designed to stay stable — field names and types don't change on the reader's end even when Goodreads' page markup does. No specific turnaround time is promised for a fix after a breaking change.

⬇️ Input

Every parameter below is read directly from .actor/actor.json. None are required individually, but the run needs at least one entry in authorTargets or bookSearchTerms — providing neither raises an error at start.

ParameterRequiredTypeConstraintsDescription
authorTargetsNoarray of stringsone per line✍️ Authors to expand. One author per line. Accepts an author name (e.g. jane austen), a Goodreads author link, or a bare author id. Each entry is expanded into that author's published titles.
booksPerAuthorNointegermin 1, max 5000, default 10📖 Titles per author. How many titles to take from each author's bibliography. Example: 2 authors × 10 = up to 20 book rows plus 2 author summary rows. Defaults to 10 when left empty.
bookSearchTermsNoarray of stringsone per line🔎 Book search terms (optional). Optional second lane: book search phrases (e.g. gothic romance) or full Goodreads search links, one per line. These produce book rows only — author summary rows are made for the author lane above.
resultsPerSearchNointegermin 1, max 10000, default 10📊 Books per search term. Target number of books for each search term above. Pages are read until this count is reached or the results run out. Defaults to 10 when left empty.
includeAuthorProfileNobooleandefault true👤 Add author profile + summary row. ON: every book row gains authorId, authorName, authorUrl, author photo, bio, follower count and total works count, and each author lane closes with one summary row. OFF: those columns stay absent from the row, and no summary row is produced.
includeSeriesInfoNobooleandefault true📚 Add series placement. ON: every book row gains isPartOfSeries, seriesTitle, seriesUrl, seriesPlacement, seriesCount and the full allSeries list. Standalone titles honestly return isPartOfSeries=false with empty series columns.
pageDelayMsNointegermin 0, max 60000, default 1000⏱️ Pause between listing pages (ms). Milliseconds to wait between listing pages. Example: 1000 = one second. Defaults to 1000 when left empty.
urlsNoarray of stringsone per line🧩 Legacy search terms. Compatibility field. Older input files that used this key keep working — the values are read as book search terms when the keyword lane above (bookSearchTerms) is empty.
resultsPerQueryNointegermin 1, max 10000🧩 Legacy books per search. Compatibility field. Used as the per-search target when the keyword lane's own count above (resultsPerSearch) is empty.
proxyConfigurationNoobject (proxy editor)prefill {"useApifyProxy": false}🌐 Network settings. Optional. Leave off for the fastest start; switch it on to route requests through Apify Proxy and pick a country if you want results from a specific region.

Example input:

{
"authorTargets": ["jane austen", "https://www.goodreads.com/author/show/1265.Brandon_Sanderson"],
"booksPerAuthor": 25,
"bookSearchTerms": ["gothic romance"],
"resultsPerSearch": 15,
"includeAuthorProfile": true,
"includeSeriesInfo": true,
"pageDelayMs": 1000,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Common pitfall: leaving authorTargets and bookSearchTerms both empty fails the run immediately — at least one is required. A second, quieter pitfall: proxyConfiguration defaults to off, but the run still falls back to Apify Proxy automatically if a direct request fails, so turning it on manually mainly controls whether the first request is proxied, not whether proxying is available at all.

⬆️ Output

Results are pushed to the Actor's default dataset as one JSON object per row, downloadable as JSON, CSV, Excel or XML. Book rows and author summary rows are pushed to the same dataset and are distinguished by the type field ("book" or "author"); a summary row also sets isChild: true. Fields that don't apply to a row (for example, book-only fields on an author summary row) are simply absent from that row rather than set to null.

Scraped book row

{
"title": "Pride and Prejudice",
"author": "Jane Austen",
"rating": "4.29",
"ratingsCount": "3,876,542",
"published": "1813",
"editions": "8,412",
"url": "https://www.goodreads.com/book/show/1885.Pride_and_Prejudice",
"coverUrl": "https://images-na.ssl-images-amazon.com/images/S/compressed.photo.goodreads.com/books/example.jpg",
"bookId": 1885,
"ratingValue": 4.29,
"ratingsCountValue": 3876542,
"publishedYear": 1813,
"authorId": 1265,
"authorName": "Jane Austen",
"authorUrl": "https://www.goodreads.com/author/show/1265.Jane_Austen",
"authorProfileImageUrl": "https://images.gr-assets.com/authors/example.jpg",
"authorBio": "Jane Austen was an English novelist known primarily for her six major novels...",
"authorFollowersCount": 142000,
"authorWorksCount": 361,
"authorRole": null,
"contributors": null,
"isPartOfSeries": false,
"seriesTitle": null,
"seriesUrl": null,
"seriesPlacement": null,
"seriesCount": 0,
"allSeries": null,
"type": "book",
"isChild": false,
"sourceType": "author_bibliography",
"sourceInput": "jane austen",
"sourceRank": 1,
"scrapedAt": "2026-08-15T09:12:41Z"
}

Scraped author summary row

{
"type": "author",
"isChild": true,
"booksCollected": 25,
"avgRatingOfCollectedBooks": 4.112,
"totalRatingsOfCollectedBooks": 9482310,
"topRatedTitle": "Pride and Prejudice",
"topRatedUrl": "https://www.goodreads.com/book/show/1885.Pride_and_Prejudice",
"topRatedRating": 4.29,
"lowestRatedTitle": "Lady Susan",
"lowestRatedUrl": "https://www.goodreads.com/book/show/12969.Lady_Susan",
"lowestRatedRating": 3.66,
"mostRatedTitle": "Pride and Prejudice",
"mostRatedUrl": "https://www.goodreads.com/book/show/1885.Pride_and_Prejudice",
"mostRatedRatingsCount": 3876542,
"earliestPublishedYear": 1811,
"latestPublishedYear": 1817,
"distinctSeriesCount": 0,
"seriesTitles": null,
"sourceType": "author_bibliography",
"sourceInput": "jane austen",
"scrapedAt": "2026-08-15T09:12:55Z",
"authorId": 1265,
"authorName": "Jane Austen",
"authorUrl": "https://www.goodreads.com/author/show/1265.Jane_Austen",
"authorProfileImageUrl": "https://images.gr-assets.com/authors/example.jpg",
"authorBio": "Jane Austen was an English novelist known primarily for her six major novels...",
"authorFollowersCount": 142000,
"authorWorksCount": 361
}

How does Goodreads Book Scraper compare to other Goodreads scrapers?

FeatureGoodreads Book ScraperGeneric alternative
Author-to-bibliography expansion✅ Give a name or link, get the full list❌ Usually keyword search only
Author summary rollup✅ One row per author (avg rating, top/lowest/most-rated, series covered)❌ Left to the user to compute downstream
Series placement per titleisPartOfSeries, seriesPlacement, full allSeries list❌ Often not extracted
Output format✅ Typed JSON (also CSV, Excel, XML)❌ Frequently raw HTML or ad hoc fields
Legacy input compatibilityurls / resultsPerQuery still accepted❌ Breaking changes on schema updates are common

If you're building an AI agent or RAG pipeline, the output format row is the decision-maker — parsing HTML inside an agent loop is a reliability failure mode, not a feature.

How many results can you scrape with Goodreads Book Scraper?

booksPerAuthor accepts 1–5000 titles per author (default 10), and resultsPerSearch accepts 1–10000 books per search term (default 10) — these input maximums are the real ceiling on a single target. Internally, the author-bibliography lane reads 30 titles per listing page and stops after 500 pages for one target as a safety limit, well above the 5,000-title input maximum, so the input value — not the page safety limit — is what actually caps a run in practice. Both lanes also stop early if Goodreads runs out of results before the target count is reached. There is no documented Goodreads-side rate limit to cite; the Actor's own retry and delay settings (pageDelayMs, up to five retry attempts per request) are the practical throttle.

Integrate Goodreads Book Scraper and automate your workflow

Goodreads Book Scraper works with any language or tool that can send an HTTP request, through the Apify API and official Apify client libraries.

REST API integration

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_API_TOKEN>")
run = client.actor("API-Empire/goodreads-book-scraper-author-bibliography-series").call(
run_input={
"authorTargets": ["jane austen"],
"booksPerAuthor": 25,
"includeAuthorProfile": True,
"includeSeriesInfo": True,
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["type"], item.get("title") or item.get("authorName"))

Works in Python, Node.js, Go, Ruby, cURL — any client that can call the Apify API. Runs can also be triggered on a schedule or from a webhook through the Apify Console, with no code required beyond the initial setup.

Scraping publicly accessible Goodreads pages is generally legal — this Actor reads only what's already visible without logging in. Two data types are returned here and they carry different considerations: book and series data (title, rating, edition count, series membership) is business/catalogue data, governed by Goodreads' Terms of Service and database-rights law rather than privacy law. Author profile fields (name, bio, photo, follower count) identify a specific person, so if you store or reuse them, treat that as personal data subject to GDPR/CCPA — have a lawful basis for holding it, and avoid using it in ways an author wouldn't reasonably expect from their own public profile. Consult legal counsel for commercial use cases involving bulk personal data.

Frequently asked questions

Does Goodreads Book Scraper work without a Goodreads account?

Yes. Every request is unauthenticated — the Actor reads public listing pages and Goodreads' own public book-data endpoint with a browser-style header. No login, cookie, or API key is required from the user.

How often is the scraped data updated?

Every run fetches live from Goodreads at the moment it executes — there is no cached snapshot. Run the Actor again (or on a schedule) to get current ratings, rankings, and bibliography changes.

What happens if an author can't be matched or a search returns nothing?

If authorTargets doesn't match a real Goodreads author, that target is skipped with a warning in the run log and the run continues with the remaining targets — no row is produced for it. If a listing page runs out of titles before the requested count is reached, the Actor stops collecting for that target early rather than erroring; the dataset simply has fewer rows than booksPerAuthor or resultsPerSearch requested.

Can I scrape private or login-gated Goodreads content?

No. Only publicly visible listing pages and book data are read. There is no login step in the Actor, so shelves, reviews, or profile details a user has restricted to signed-in visitors are not accessible.

Does Goodreads Book Scraper work for AI agent workflows and LLM pipelines?

Yes, as an HTTP-callable Apify Actor — call it through the Apify API or apify-client from any agent framework. Every response is typed JSON with stable field names (title, ratingValue, seriesTitle, authorBio, and so on), so it can be passed directly into an LLM context window or indexed into a vector store without a parsing step.

How does Goodreads Book Scraper handle Goodreads' anti-bot defenses?

It retries failed requests up to five times with a short backoff between attempts, and for listing pages specifically, it treats a short "interstitial" response (below roughly 20KB and missing the results table marker) as a failed attempt rather than as "no more results," retrying it on a fresh Apify Proxy address instead of silently truncating the listing. Apify Proxy (residential group by default) is used as an automatic fallback on failure even when the proxyConfiguration input is left off.

Does Goodreads Book Scraper return data in a format LLMs can use directly?

Yes. Output is typed, normalized JSON with stable field names — no HTML, no CSS selectors. Pass it directly into an LLM prompt, a RAG index, or an agent tool call.

Can I use Goodreads Book Scraper without managing proxies?

Yes. Apify Proxy is wired in as a retry fallback automatically; you only need to configure proxyConfiguration yourself if you want to force proxy use from the first request or pick a specific country.

What happens when Goodreads changes its structure or blocks the scraper?

The Actor is maintained, and the output schema stays stable on the reader's end — field names and types don't change even when Goodreads' page markup does. No numeric turnaround time is promised for a given fix.

💬 Your feedback

Found a bug, or missing a field you need in the book, author, or series data? We want to know — open an issue through the Actor's page on the Apify Store or message API-Empire directly through Apify Console. Reports like this are how the field list above stays accurate as Goodreads' own pages change.