Goodreads Books Scraper avatar

Goodreads Books Scraper

Pricing

from $1.11 / 1,000 books

Go to Apify Store
Goodreads Books Scraper

Goodreads Books Scraper

Search Goodreads by title, author or keyword and get one row per book: title with its series, author, average rating, how many people rated it, the listed edition's year, full-size cover and link. Up to 20 terms a run. No account. $1.14 per 1,000 books.

Pricing

from $1.11 / 1,000 books

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 days ago

Last modified

Categories

Share

Type a title, an author or a plain keyword and get Goodreads search results back as rows: title, author, average rating, how many people rated it, the year of the edition Goodreads lists, the full-size cover and the book link.

What it gives you is the search listing, not the book page. That means ratings and counts, and it means no blurb, no ISBN, no genres and no reviews. The listing also does not show a book's first publication year or its edition count, so those two columns are always empty.

InputTitles, authors or keywords, up to 20 per run
OutputOne row per book: title with its series, author, average rating, ratings count, listed edition's year, cover, link
Ceiling2,000 books per run
Account neededNone, no API key, no browser
Price$1.14 per 1,000 books on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 4,300

🔍 What Goodreads Books Scraper does

It runs each of your search terms and pages through the results until it has your share of the row budget. The budget is split evenly between terms, so four terms and 40 rows gives you ten of each rather than 40 of the first one.

searchField changes the answer more than it looks. Searching christie as an author gives you Agatha Christie's novels. The same word as a title gives you books with Christie in the name. Those are genuinely different result sets, not the same set reordered.

Two things it refuses to bill you for. A book Goodreads lists without a rating is skipped, because a row with no rating is the thing you came for missing. And "Goodreads looked and found nothing" is a real answer, kept separate from "the request never got through", so a term that genuinely has no matches is not charged as rows.

Goodreads serves 20 books per search page, and its deep pages start handing back books you have already seen. Paging stops at 50 pages per term, which is past where distinct results ran out in testing.

📋 What data you get from each Goodreads book

What you getField
Goodreads' id for the book, and its linkbookId, url
The title as listed, series marker includedtitle
The authorauthor
Average rating and how many ratings it rests onavgRating, ratingsCount
The year of the edition the listing showseditionPublishedYear
The full-size covercoverUrl
Which term found it, how, and at what positionquery, searchField, rank
When it was readscrapedAt

▶️ How to scrape Goodreads books

  1. Open Goodreads Books Scraper and click Try for free.
  2. Put one term per line into Search terms.
  3. Pick Search in if you want author-only or title-only matching.
  4. Set Maximum rows. Start at 20 to see the shape of the output.
  5. Click Start, then download the dataset as JSON, CSV or Excel, or read it from the Apify API.

Start it with no search terms and you get one labelled sample row instead, which is not charged.

💰 How much does it cost to scrape Goodreads?

$1.14 per 1,000 books on the Free plan. Paid plans pay a little less: $1.13 on Starter, $1.12 on Scale and $1.11 on Business. On the free plan, the $5 Apify gives you each month covers about 4,300 books.

You pay per book row delivered. Duplicates across terms, books skipped for having no rating, the sample row, diagnostic rows and a term that finds nothing are not charged.

📥 What you give it

{
"queries": ["dune", "project hail mary"],
"searchField": "all",
"maxItems": 20
}
FieldDefaultWhat it is
queriesnone, the form starts with dune and project hail maryTitles, author names or keywords, one per line, up to 20. Each is searched in turn.
searchFieldallall is Goodreads' own default and mixes titles, authors and series. title and author return different sets.
maxItems20Total books across every term, up to 2,000, shared evenly between them. This is also your spending cap.
proxyUrlsnoneLeave it empty unless you have your own servers you want the traffic to leave through, one URL per line as http://user:pass@host:port.

📤 What you get back

A real row from a run on 2 October 2026:

{
"ok": true,
"charged": true,
"recordType": "book",
"query": "dune",
"searchField": "all",
"rank": 1,
"bookId": "44767458",
"title": "Dune (Dune, #1)",
"author": "Frank Herbert",
"avgRating": 4.29,
"ratingsCount": 1714417,
"publishedYear": null,
"editionPublishedYear": 2019,
"editionsCount": null,
"url": "https://www.goodreads.com/book/show/44767458",
"coverUrl": "https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1555447414i/44767458.jpg",
"scrapedAt": "2026-10-02T23:23:22.478Z"
}
FieldHow to read it
bookIdGoodreads' own id for the work. Stable, so use it to dedupe across runs.
avgRating, ratingsCountThe average out of five and how many ratings it is built on. Every delivered row has both.
editionPublishedYearThe year the edition Goodreads lists was published. For a reissue that is the reissue's year (2019 for the Dune above), not the year the book first came out.
publishedYear, editionsCountAlways null. The search listing does not show the first publication year or the edition count. The columns stay so anything built on them keeps working.
titleAs listed, series marker and all, like Dune (Dune, #1).
coverUrlThe full-size cover image on Goodreads' own servers.

🧾 Reading the output

Three kinds of row can land in your dataset, and recordType tells them apart.

RowHow to spot itBilled
A bookrecordType: "book"yes
The sample row_sample: true, recordType: "sample"no
A diagnostic_diagnostic: true and an errorCodeno

The charged field is a label, not a receipt. It is stamped when the row is built, before billing happens, so read it the way you read recordType: it separates real books from sample and diagnostic rows, nothing more.

CodeWhat it means
NO_RESULTSGoodreads has nothing matching that term. A real answer, and not charged.
ROW_INCOMPLETEA book was listed without a rating, so it was skipped rather than delivered. Not charged.
TIME_BUDGETThe run ran out of time before reaching a term. Everything already delivered is complete.
NOT_SERVEDThis book was not served this run. Re-run it later. Until 12 October 2026 this code was called BLOCKED.
NETWORKGoodreads was unreachable. Re-run it.
PROXY_INPUT_ADJUSTEDA connection setting in your input was not usable, so the run used its own.
CHARGE_ERRORBilling could not be recorded for some rows. Rare, and worth telling us about.

One bad term never stops the others, and a diagnostic row never fails the run.

💡 What people use it for

  • Checking how an author's back catalogue is rated, by searching them with searchField set to author and sorting on ratingsCount.
  • Building a shortlist for a reading list or a shop buy, where avgRating alone is misleading and ratingsCount is the number that matters.
  • Watching how a new release gathers ratings week by week, scheduled and deduped on bookId.
  • Resolving a messy list of titles to real Goodreads links and ids before enriching them elsewhere.

🚧 What it does not do

  • Search results only. No blurb, no ISBN, no genres, no page count, no publisher.
  • No reviews and no reviewer data. Only the rating average and the count.
  • No user shelves, no lists, no author pages, and nothing that needs a Goodreads login.
  • Books with no rating are skipped, so a very obscure or just-announced title may not appear.
  • 50 pages per term. Goodreads' deep pages repeat, so a single term will not yield thousands of distinct books however high you set maxItems.
  • No first publication year and no edition count. editionPublishedYear is the year of the edition the listing shows, which for a classic can be decades after it first came out.
  • Relevance order is Goodreads', applied before paging, so asking for 20 gives you the 20 it serves first.
  • It is not an official Goodreads tool. Dami's Studio is independent and is not affiliated with or endorsed by Goodreads or Amazon, or by any other company named on this page.

🧭 Which reference scraper do you need?

If you wantUse
Wikipedia search results or article textWikipedia Scraper
Wikidata Q-ids, aliases and claims, by name or by IDWikidata Scraper
Book metadata by keyword, title or ISBNBooks Scraper
Goodreads ratings and rating counts from a book searchThis one
Books, audio, film and software held on archive.orgInternet Archive Scraper
Papers with readable abstracts and citation countsOpenAlex Scraper
Wikipedia, arXiv and OpenAlex searches as tools for an AI agentResearch MCP Server

❓ Questions people ask

Do I need a Goodreads account or an API key?

Neither. The search listing needs no login.

Can I get the book description or the ISBN?

Not from here. Books Scraper covers ISBN, publisher and page count.

Why do author and title searches give different books?

Because they are different searches. author matches the writer, title matches words in the name of the book.

Why did I get fewer rows than I asked for?

Either the terms ran out of distinct results, or some books had no rating and were skipped. The diagnostic rows say which.

Why does the rating count differ from the Goodreads page?

Ratings keep arriving every day, so a row is a snapshot. Compare it with the page at the time in scrapedAt, not with what the page says an hour later.

Can I call it from code or connect it to an AI assistant?

Yes. The API tab has ready-made code for Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/goodreads-books-scraper. Either way the run happens on your Apify account at the same price.

These are public catalogue pages. Author names are personal data under GDPR, so have a reason for collecting them. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.

🆘 If something breaks

Open the Issues tab on the actor page. Send the run ID and the search term you used. The errorCode on the diagnostic row usually names the problem on its own.