# Goodreads Scraper - Books, Ratings, Reviews & ISBN (`scrapewise/goodreads-scraper`) Actor

Scrape Goodreads books by search, ISBN, book, list, shelf, genre or author page: title, author, series, genres, rating, rating distribution, ratings and reviews count, readers, pages, publisher, ISBN, ASIN, awards, characters. Optional top reviews with text and likes.

- **URL**: https://apify.com/scrapewise/goodreads-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** E-commerce, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.52 / 1,000 book delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Goodreads Scraper - Books, Ratings, Reviews & ISBN

**Scrape Goodreads books without a login: title, authors with followers, series and position, description, genres, average rating, the full 1 to 5 star distribution, ratings and reviews count, reviews per language, how many people are reading it and want to read it, format, pages, publisher, publication and first publication dates, language, ISBN, ISBN-13, ASIN, awards, characters, places, quotes count, Kindle price and cover. Search by title, author or ISBN, or paste book, Listopia list, shelf, genre and author pages. Turn on reviews to also get the top reviews of each book with stars, text, likes and comments.**

For publishers and literary agents tracking titles and comps, authors and marketers watching ratings and reader demand, booksellers enriching catalogs with ISBN and genres, recommendation and reading apps, and researchers who need book metadata and review text at scale.

### Goodreads scraper at a glance

- **Price:** US$ 2.00 per 1,000 books on the Free plan, plus US$ 0.003 per run; reviews US$ 1.00 per 1,000
- **Every way in:** search terms, ISBN-10 and ISBN-13, book pages, Listopia lists, shelves, genres, author pages and search pages, with pagination
- **Full book record from the book page:** not just the title and rating from a list, but the rating distribution, readers, awards, characters, editions link and more
- **Reader demand signals:** currently reading and want to read counts for every book
- **Reviews as rows:** up to 30 top reviews per book, filterable by star rating; reviewer names are never collected
- **Filters:** minimum average rating
- **No login, no browser.** Wrong links and empty searches return free error rows

### Quick start

```json
{
  "searchQuery": ["the midnight library"],
  "maxItems": 30
}
```

A genre shelf with its 5-star reviews:

```json
{
  "startUrls": ["https://www.goodreads.com/shelf/show/fantasy"],
  "maxItems": 100,
  "includeReviews": true,
  "maxReviewsPerBook": 10,
  "reviewRating": 5
}
```

ISBN lookup:

```json
{
  "searchQuery": ["9780525559474", "0525559477"]
}
```

### Input

| Field | What it does |
|---|---|
| `searchQuery` | Titles, authors, topics or ISBNs, one per line. An ISBN returns that book. |
| `startUrls` | goodreads.com book, list (`/list/show/...`), shelf (`/shelf/show/...`), genre, author or search pages. |
| `maxItems` | Cap per search term or listing link. 0 = no cap. Default 30. |
| `minRating` | Only books with at least this average rating. |
| `includeReviews` | Also deliver the top reviews of each book as rows. |
| `maxReviewsPerBook` | Up to 30. |
| `reviewRating` | Only reviews with this star rating (1 to 5). |
| `proxyConfiguration` | Apify Proxy by default. |

Field names used by other Goodreads tools (`search`, `searchTerms`, `isbns`, `targets`, `maxBooksPerListing`) are accepted too, so an existing Task or integration keeps working after you switch.

### Example output

A real book row from a run of 23 Oct 2026 (description and review languages shortened):

```json
{
  "type": "book",
  "bookId": "52578297",
  "title": "The Midnight Library",
  "titleComplete": "The Midnight Library (The Midnight World, #1)",
  "url": "https://www.goodreads.com/book/show/52578297-the-midnight-library",
  "author": "Matt Haig",
  "authors": [
    {"name": "Matt Haig", "role": "Author", "authorId": "76360", "followers": 53510, "worksCount": 86, "isGoodreadsAuthor": true}
  ],
  "series": [{"name": "The Midnight World", "position": "1", "url": "https://www.goodreads.com/series/433132-the-midnight-world"}],
  "description": "Between life and death there is a library...",
  "genres": ["Fiction", "Fantasy", "Book Club", "Contemporary", "Magical Realism"],
  "averageRating": 3.97,
  "ratingsCount": 2706865,
  "reviewsCount": 271391,
  "ratingDistribution": {"1": 42575, "2": 155010, "3": 576343, "4": 1005260, "5": 927677},
  "reviewLanguages": {"en": 223844, "es": 17548, "pt": 3357, "de": 2535},
  "currentlyReading": 126076,
  "wantToRead": 2068278,
  "format": "Hardcover",
  "pages": 288,
  "publisher": "Viking",
  "publishedDate": "2020-09-29",
  "firstPublishedDate": "2020-08-13",
  "language": "English",
  "isbn": "0525559477",
  "isbn13": "9780525559474",
  "awards": [{"name": "Goodreads Choice Award", "category": "Fiction", "designation": "WINNER", "year": "2020"}],
  "characters": ["Nora Seed"],
  "places": ["Bedford, Bedfordshire, England"],
  "quotesCount": 2048,
  "kindlePrice": 10.99,
  "imageUrl": "https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1602190253i/52578297.jpg",
  "editionsUrl": "https://www.goodreads.com/work/editions/74043794",
  "sourceUrl": "https://www.goodreads.com/search?q=the+midnight+library&search_type=books",
  "scrapedAt": "2026-10-23T13:05:15Z"
}
```

A review row from the same run (text shortened):

```json
{
  "type": "review",
  "reviewId": "JA77MS_6MKamFAQ1HbuuLQ",
  "bookId": "52578297",
  "bookTitle": "The Midnight Library",
  "rating": 2,
  "text": "Edited 5/31/25: ...",
  "hasSpoilers": false,
  "likes": 9080,
  "comments": 772,
  "createdAt": "2021-01-05T05:27:49Z",
  "updatedAt": "2025-06-21T20:53:47Z"
}
```

### What data the Goodreads scraper returns

| Field | What it is |
|---|---|
| `bookId`, `title`, `titleComplete`, `originalTitle`, `url` | The book and its page |
| `author`, `authors` | Main author, plus every contributor with role, id, followers and works count |
| `series` | Series name, position and link |
| `description`, `genres` | Blurb and Goodreads genres |
| `averageRating`, `ratingsCount`, `reviewsCount`, `ratingDistribution` | Ratings, with the count for each star |
| `reviewLanguages` | Number of text reviews per language |
| `currentlyReading`, `wantToRead` | Readers shelving the book right now |
| `format`, `pages`, `publisher`, `publishedDate`, `firstPublishedDate`, `language` | Edition details |
| `isbn`, `isbn13`, `asin` | Identifiers |
| `awards`, `characters`, `places`, `quotesCount` | Literary awards, characters, settings and number of quotes |
| `kindlePrice`, `imageUrl`, `workId`, `editionsUrl` | Kindle price shown, cover, work id and all editions |
| Review rows: `reviewId`, `bookId`, `bookTitle`, `rating`, `text`, `hasSpoilers`, `likes`, `comments`, `createdAt`, `updatedAt` | With `includeReviews` on |
| `sourceUrl` | The search or page that found the book |

Fields that are empty for a book are left out of its row. Reviewer names, profiles and photos are never collected.

### Pricing

Pay per event, no monthly fee.

| Event | Free plan price |
|---|---|
| Book delivered | US$ 0.002 (US$ 2.00 per 1,000) |
| Review delivered (only with `includeReviews`) | US$ 0.001 (US$ 1.00 per 1,000) |
| Actor start | US$ 0.003 per run |

| Job | Cost at the Free plan price |
|---|---|
| 30 books for one search | about US$ 0.06 |
| 1,000 books from a Listopia list | about US$ 2.00 |
| 100 books with 30 reviews each | about US$ 3.20 |

Error rows, duplicates and books below your minimum rating are never charged.

### Errors

| `errorCode` | Meaning |
|---|---|
| `INVALID_URL` | The link is not a supported goodreads.com page |
| `NOT_FOUND` | The book or page does not exist |
| `NO_RESULTS` | No books for this search |
| `INVALID_INPUT` | A value in the input is not valid |
| `BLOCKED` | The site did not answer after several tries; run again |
| `NOT_REACHED` | The run stopped (time, spending limit) before this source |

### Integrations, scheduling and AI agents

- **Schedules:** run a Task weekly on your titles or a genre shelf to track ratings, readers and new reviews over time.
- **Export** to JSON, CSV, Excel or HTML from the dataset, or read it through the Apify API.
- **Make, n8n, Zapier** and webhooks: send ratings to Google Sheets, Airtable or a dashboard.
- **AI agents:** the Actor works through the Apify MCP server, so an agent can ask "how is this novel rated, what genres is it, and what do top reviews complain about?" and get structured rows back.

### FAQ

**How many reviews can I get per book?** Up to 30, the top reviews Goodreads shows on the book page (most popular first).

**Can I search by ISBN?** Yes, ISBN-10 or ISBN-13 in `searchQuery` returns that book.

**Which list pages work?** Listopia lists, shelves (`/shelf/show/fantasy`), genres, author book lists (`/author/list/...` or the author page) and search pages, with pagination.

**Does it need a Goodreads account?** No.

**Is it legal to scrape Goodreads?** The Actor reads public book pages without logging in and does not collect personal data of reviewers. You are responsible for how you use the data.

### Limitations

- Reviews are the top 30 shown on each book page; older reviews beyond those are not collected.
- Quotes, questions and discussion topics are counted, not collected.

If this Actor saves you time, a short review on the Store page helps other people find it.

### Related scrapers

- [Trustpilot Reviews Scraper](https://apify.com/scrapewise/trustpilot-reviews-scraper): company reviews.
- [Google Shopping Scraper](https://apify.com/scrapewise/google-shopping): product prices across stores.
- [YouTube Transcript Scraper](https://apify.com/scrapewise/youtube-transcript): video transcripts.

### Changelog

- **23 Oct 2026, 0.1:** first release. Search, ISBN, book, list, shelf, genre and author pages, full book records with rating distribution and readers, top reviews.

This Actor collects only publicly available data. Independent tool, not affiliated with Goodreads or Amazon.

# Actor input Schema

## `searchQuery` (type: `array`):

Book titles, authors, topics or ISBN-10/ISBN-13 numbers, one per line. An ISBN returns that book.

## `startUrls` (type: `array`):

Optional: goodreads.com book pages, Listopia lists, shelves, genres, author pages or search pages, one per line.

## `maxItems` (type: `integer`):

Cap for each search term or listing link, following the site's pages. 0 = no cap. Default 30.

## `minRating` (type: `string`):

Optional: only books with at least this average rating, for example 4 or 4.2. Books below are free.

## `includeReviews` (type: `boolean`):

On: also deliver the top reviews shown on each book page (up to 30 per book) as separate rows. Adds the 'Review delivered' charge per review.

## `maxReviewsPerBook` (type: `integer`):

Up to 30 per book (the reviews Goodreads shows on the book page, most popular first).

## `reviewRating` (type: `integer`):

Optional: 1 to 5.

## `proxyConfiguration` (type: `object`):

Apify Proxy by default. Change it only if you know you need to.

## Actor input object example

```json
{
  "searchQuery": [
    "the midnight library"
  ],
  "maxItems": 30,
  "includeReviews": false,
  "maxReviewsPerBook": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsCsv` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQuery": [
        "the midnight library"
    ],
    "maxItems": 30,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/goodreads-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQuery": ["the midnight library"],
    "maxItems": 30,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/goodreads-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQuery": [
    "the midnight library"
  ],
  "maxItems": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/goodreads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapewise/goodreads-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jNWzOGCDFFNWLQDAw/builds/NdsponUSZ4Ty8bIE4/openapi.json
