# Goodreads Scraper (`maximedupre/goodreads-scraper`) Actor

Scrape public Goodreads books from search terms, book URLs, shelves, genres, lists, and author pages. Export ratings, authors, ISBNs, descriptions, covers, source ranks, and optional review rows.

- **URL**: https://apify.com/maximedupre/goodreads-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 goodreads books

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

### 📚 Goodreads scraper for books, shelves, and reviews

Goodreads Scraper collects public book data from [Goodreads](https://www.goodreads.com/) search terms, ISBNs, book URLs, shelves, genres, lists, search pages, author pages, and series pages. Add a Goodreads URL, ISBN, or a query such as `science fiction`, then export book titles, authors, ratings, review counts, descriptions, ISBNs, genres, covers, and scrape metadata from a clean Apify dataset.

Use this Goodreads scraper when you need repeatable book data for market research, reading-list curation, publishing research, recommendation datasets, SEO briefs, content planning, or internal book intelligence workflows. You can run it in Apify Console, schedule repeat runs, call it from the Apify API, and export results as JSON, CSV, Excel, XML, RSS, or HTML.

The Actor is built for public Goodreads pages. It does not require a Goodreads account, cookies, Goodreads API key, or user credentials. It only saves usable scraped results; invalid targets, unavailable pages, and source-side problems are reported in logs instead of placeholder dataset rows.

### ✅ What this Actor does

- Scrapes Goodreads book results from search terms.
- Looks up books by ISBN-10 or ISBN-13.
- Scrapes public Goodreads book, shelf, genre, list, search, author, and series URLs.
- Saves one dataset item per discovered book.
- Optionally saves public review rows found on book pages.
- Optionally saves author, list, and series metadata rows.
- Filters books by rating, ratings count, publish year, language, genre, and author.
- Opens book pages for detail enrichment when `includeBookDetails` is enabled.
- Keeps source URL, source type, source rank, and scrape time on every book row.
- Deduplicates books across all submitted searches and URLs by default.
- Stops at your `maxItems`, `maxPages`, and `maxReviewsPerBook` limits.

For keyword search, the Actor uses Goodreads public autocomplete results. For shelf, genre, list, search URL, and author targets, it discovers book links from the submitted Goodreads pages and then enriches each book from its public book page.

### 📦 Data you can extract

Each `book` output item can include:

- `goodreadsId`, `url`, and `canonicalUrl`
- `title`
- `authors` with author name, URL, and Goodreads ID when available
- `rating`, `ratingCount`, and `reviewCount`
- `description`
- `imageUrl`
- `isbn` and `isbn13`
- `publisher`, `publishedDate`, and `firstPublishedDate`
- `pageCount`, `bookFormat`, and `language`
- `series`, `genres`, `characters`, and `awards`
- `buyLinks` when available
- `sourceTargetUrl`, `sourceTargetType`, `sourcePage`, and `sourceRank`
- `status`, `missingFields`, and `scrapedAt`

When `includeReviews` is enabled and `maxReviewsPerBook` is greater than `0`, the Actor can also save `review` rows with the source book URL, visible reviewer profile data, visible review text, HTML, shelves when available, and scrape time.

When `includeMetadata` is enabled, author, list, and series URL targets can also emit `metadata` rows with `metadataType`, source URL, title, description, book count when visible, and scrape time.

Some Goodreads pages do not expose every field for every book. Missing scalar values are returned as `null`, and missing lists are returned as empty arrays. The Actor does not invent metadata that is not visible in the public source page.

### 🚀 How to run

1. Add one or more Goodreads search terms, ISBNs, Goodreads URLs, or a mix of all three.
2. Keep `Book limit` at `25` or `50` for a quick first run.
3. Keep `Page limit per target` low while testing shelf, genre, list, or author pages.
4. Leave `Include book details` on if you want descriptions, ISBNs, page counts, genres, ratings, and review counts.
5. Turn on `Include reviews` only when you need review rows, then set a small `Review limit per book`.
6. Run the Actor and open the dataset in Apify Console, export it, or pull it through the Apify API.

For the fastest first run, use the prefilled `science fiction` search term or the prefilled `https://www.goodreads.com/shelf/show/fantasy` shelf URL with a small book limit.

### ⚙️ Input

```json
{
	"searchTerms": ["science fiction"],
	"isbns": ["9780062316097"],
	"targets": [
		{
			"url": "https://www.goodreads.com/series/45175-harry-potter"
		}
	],
	"maxItems": 25,
	"maxPages": 2,
	"includeBookDetails": true,
	"includeReviews": false,
	"maxReviewsPerBook": 0,
	"includeMetadata": true,
	"minRating": 3.5,
	"minRatingsCount": 10,
	"deduplicateBooks": true
}
````

#### 🔎 Search terms

Use plain Goodreads book searches such as:

- `science fiction`
- `romantasy`
- `Stephen King`
- `business books`
- `historical fiction`

Each search term is searched separately. Empty and duplicate terms are ignored.

#### 🔢 ISBNs

Use ISBN-10 or ISBN-13 values such as:

- `9780062316097`
- `978-0-7432-7356-5`
- `0747532699`

Hyphens and spaces are accepted. Each ISBN is searched on Goodreads and saved as a book row when Goodreads returns a public match.

#### 🔗 Goodreads URLs

You can submit public Goodreads URLs such as:

- Book pages: `https://www.goodreads.com/book/show/5907.The_Hobbit`
- Shelf pages: `https://www.goodreads.com/shelf/show/fantasy`
- Genre pages: `https://www.goodreads.com/genres/most_read/fantasy`
- List pages: `https://www.goodreads.com/list/show/1.Best_Books_Ever`
- Series pages: `https://www.goodreads.com/series/45175-harry-potter`
- Search pages, author pages, and author book-list pages

The Actor skips unsupported or unavailable targets instead of saving fake rows.

#### 🎚️ Limits and options

`maxItems` caps saved book rows across the whole run. `maxPages` caps listing pages scanned for each Goodreads URL target. `includeBookDetails` controls whether the Actor opens each book page for enriched fields. `includeReviews` and `maxReviewsPerBook` control optional review row output. `includeMetadata` controls optional author/list/series summary rows. `deduplicateBooks` keeps the same Goodreads book from being saved more than once in a run.

Filters apply when the relevant field is visible on Goodreads: `minRating`, `minRatingsCount`, `publishYearMin`, `publishYearMax`, `language`, `containsGenre`, and `containsAuthor`.

### 🧪 Output example

```json
{
	"rowType": "book",
	"goodreadsId": "5907",
	"url": "https://www.goodreads.com/book/show/5907.The_Hobbit",
	"canonicalUrl": "https://www.goodreads.com/book/show/5907.The_Hobbit",
	"title": "The Hobbit, or There and Back Again",
	"authors": [
		{
			"name": "J.R.R. Tolkien",
			"url": "https://www.goodreads.com/author/show/656983.J_R_R_Tolkien",
			"goodreadsId": "656983"
		}
	],
	"rating": 4.29,
	"ratingCount": 4510933,
	"reviewCount": 74706,
	"description": "Bilbo Baggins is a hobbit who enjoys a comfortable, unambitious life...",
	"imageUrl": "https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1546071216i/5907.jpg",
	"isbn": "9780547928227",
	"isbn13": null,
	"publisher": null,
	"publishedDate": null,
	"firstPublishedDate": "First published September 21, 1937",
	"pageCount": 366,
	"bookFormat": "Paperback",
	"language": "English",
	"series": null,
	"genres": ["Fantasy", "Classics", "Fiction"],
	"characters": [],
	"awards": [],
	"buyLinks": [],
	"sourceTargetUrl": "https://www.goodreads.com/shelf/show/fantasy",
	"sourceTargetType": "shelf",
	"sourcePage": 1,
	"sourceRank": 1,
	"status": "ok",
	"missingFields": [],
	"scrapedAt": "2026-05-27T19:17:00.000Z"
}
```

### 💳 Pricing

This Actor uses pay-per-event pricing. You are charged for each saved Goodreads book. If you enable review scraping, each saved Goodreads review is charged separately. If you enable author/list/series metadata, each saved metadata row is charged separately.

Book and metadata pricing by Apify tier:

| Tier | Price per 1,000 |
| --- | ---: |
| FREE | $1.80 |
| BRONZE | $1.50 |
| SILVER | $1.15 |
| GOLD | $0.90 |
| PLATINUM | $0.90 |
| DIAMOND | $0.90 |

Review rows are $0.90 per 1,000.

Review scraping can create many more rows than book scraping, so keep `maxReviewsPerBook` small for your first review run.

### ⚠️ Limits and caveats

- The Actor works with public Goodreads data only.
- It does not scrape private Goodreads data, logged-in-only pages, or account-specific shelves.
- Review extraction is best for visible public review cards on book pages; it does not guarantee every review for books with large review histories.
- Source pages can change, omit fields, or temporarily return no usable data. In those cases, the Actor saves available book rows and reports problems in logs.
- Large runs over shelves, genres, lists, or authors should use bounded limits first, then scale after you inspect the output shape.

### ❓ FAQ

#### 🔐 Do I need a Goodreads account?

No. The Actor is designed for public Goodreads pages and does not ask for Goodreads cookies, credentials, or an API key.

#### 💬 Can I scrape Goodreads reviews?

Yes. Turn on `Include reviews` and set `Review limit per book` above `0`. Review rows are separate from book rows so CSV and spreadsheet exports stay easier to work with.

#### 🔗 Can I use direct Goodreads book URLs?

Yes. Add public Goodreads book URLs to `Goodreads URLs`. You can also add shelves, genres, lists, search pages, and author book-list pages.

#### 🧩 Why are some fields null?

Goodreads does not expose every field on every public page. The Actor keeps missing values as `null` or empty arrays rather than guessing.

#### 🗓️ Can I schedule this Goodreads scraper?

Yes. After you save an input, you can schedule repeat Apify runs, call the Actor through the Apify API, or connect results to downstream tools with Apify integrations and webhooks.

### 📝 Changelog

- 0.2: Added ISBN lookup, series URLs, optional author/list/series metadata rows, book filters, and lower tiered pay-per-event pricing.
- 0.1: Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~goodreads-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Other actors

- [Product Hunt Scraper ↗](https://apify.com/maximedupre/product-hunt-scraper) - Find startup launches, ranks, followers, reviews, and optional website details.
- [Reddit Scraper ↗](https://apify.com/maximedupre/reddit-scraper) - Search Reddit posts and comments for research, monitoring, and conversation tracking.
- [Quora Search Scraper ↗](https://apify.com/maximedupre/quora-search-scraper) - Find public Quora questions from search terms or direct question URLs.
- [Website URL Crawler ↗](https://apify.com/maximedupre/website-url-crawler) - Crawl rendered websites and export link maps for SEO, QA, and audits.
- [Unsplash Image Scraper ↗](https://apify.com/maximedupre/unsplash-image-scraper) - Collect Unsplash image search results with source ranks and image URLs.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `searchTerms` (type: `array`):

Enter Goodreads book searches such as science fiction, romantasy, Stephen King, or business books. Each term is searched separately.

## `isbns` (type: `array`):

Enter ISBN-10 or ISBN-13 values. Hyphens and spaces are fine; each ISBN is searched on Goodreads and the matching book is saved when found.

## `targets` (type: `array`):

Paste public Goodreads book, shelf, genre, list, search, author, or series URLs. Use one shelf or genre URL for a simple first URL run.

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

Maximum Goodreads book rows to save across all searches and URLs.

## `maxPages` (type: `integer`):

Maximum listing pages to scan for each Goodreads shelf, genre, list, author, or search URL.

## `includeBookDetails` (type: `boolean`):

Open each book page to add fields such as description, ISBN, language, page count, awards, rating count, and review count.

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

Also save visible public Goodreads review rows found on each book page. Leave off unless you need review text.

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

Maximum Goodreads review rows to save for each book when reviews are enabled. Use a small number for first review runs.

## `includeMetadata` (type: `boolean`):

Also save summary rows for Goodreads author, list, and series targets when available.

## `minRating` (type: `number`):

Only save books whose Goodreads average rating is at least this value.

## `minRatingsCount` (type: `integer`):

Only save books with at least this many Goodreads ratings.

## `publishYearMin` (type: `integer`):

Only save books first published in or after this year when Goodreads exposes a year.

## `publishYearMax` (type: `integer`):

Only save books first published in or before this year when Goodreads exposes a year.

## `language` (type: `string`):

Only save books whose Goodreads language field contains this text, such as English or en.

## `containsGenre` (type: `string`):

Only save books with at least one genre containing this text.

## `containsAuthor` (type: `string`):

Only save books with at least one author name containing this text.

## `deduplicateBooks` (type: `boolean`):

Save each Goodreads book once even if it appears in multiple submitted searches or URLs.

## Actor input object example

```json
{
  "searchTerms": [
    "science fiction"
  ],
  "isbns": [
    "9780062316097"
  ],
  "targets": [
    {
      "url": "https://www.goodreads.com/shelf/show/fantasy"
    }
  ],
  "maxItems": 25,
  "maxPages": 3,
  "includeBookDetails": true,
  "includeReviews": false,
  "maxReviewsPerBook": 0,
  "includeMetadata": false,
  "deduplicateBooks": true
}
```

# Actor output Schema

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

Open the dataset with Goodreads book titles, authors, ratings, review counts, source ranks, optional review rows, and optional metadata rows.

# 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 = {
    "searchTerms": [
        "science fiction"
    ],
    "isbns": [
        "9780062316097"
    ],
    "targets": [
        {
            "url": "https://www.goodreads.com/shelf/show/fantasy"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/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 = {
    "searchTerms": ["science fiction"],
    "isbns": ["9780062316097"],
    "targets": [{ "url": "https://www.goodreads.com/shelf/show/fantasy" }],
}

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

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

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

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "science fiction"
  ],
  "isbns": [
    "9780062316097"
  ],
  "targets": [
    {
      "url": "https://www.goodreads.com/shelf/show/fantasy"
    }
  ]
}' |
apify call maximedupre/goodreads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=maximedupre/goodreads-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Goodreads Scraper",
        "description": "Scrape public Goodreads books from search terms, book URLs, shelves, genres, lists, and author pages. Export ratings, authors, ISBNs, descriptions, covers, source ranks, and optional review rows.",
        "version": "0.2",
        "x-build-id": "JfTSxhOdtxTbS9eXY"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/maximedupre~goodreads-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-maximedupre-goodreads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/maximedupre~goodreads-scraper/runs": {
            "post": {
                "operationId": "runs-sync-maximedupre-goodreads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/maximedupre~goodreads-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-maximedupre-goodreads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchTerms": {
                        "title": "Search terms",
                        "type": "array",
                        "description": "Enter Goodreads book searches such as science fiction, romantasy, Stephen King, or business books. Each term is searched separately.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "isbns": {
                        "title": "ISBNs",
                        "type": "array",
                        "description": "Enter ISBN-10 or ISBN-13 values. Hyphens and spaces are fine; each ISBN is searched on Goodreads and the matching book is saved when found.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "targets": {
                        "title": "Goodreads URLs",
                        "type": "array",
                        "description": "Paste public Goodreads book, shelf, genre, list, search, author, or series URLs. Use one shelf or genre URL for a simple first URL run.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL",
                                    "description": "A public Goodreads book, shelf, genre, list, search, author book-list, or series URL."
                                }
                            }
                        }
                    },
                    "maxItems": {
                        "title": "Book limit",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum Goodreads book rows to save across all searches and URLs.",
                        "default": 25
                    },
                    "maxPages": {
                        "title": "Page limit per target",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum listing pages to scan for each Goodreads shelf, genre, list, author, or search URL.",
                        "default": 3
                    },
                    "includeBookDetails": {
                        "title": "Include book details",
                        "type": "boolean",
                        "description": "Open each book page to add fields such as description, ISBN, language, page count, awards, rating count, and review count.",
                        "default": true
                    },
                    "includeReviews": {
                        "title": "Include reviews",
                        "type": "boolean",
                        "description": "Also save visible public Goodreads review rows found on each book page. Leave off unless you need review text.",
                        "default": false
                    },
                    "maxReviewsPerBook": {
                        "title": "Review limit per book",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum Goodreads review rows to save for each book when reviews are enabled. Use a small number for first review runs.",
                        "default": 0
                    },
                    "includeMetadata": {
                        "title": "Include author/list/series metadata",
                        "type": "boolean",
                        "description": "Also save summary rows for Goodreads author, list, and series targets when available.",
                        "default": false
                    },
                    "minRating": {
                        "title": "Minimum average rating",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "number",
                        "description": "Only save books whose Goodreads average rating is at least this value."
                    },
                    "minRatingsCount": {
                        "title": "Minimum ratings count",
                        "minimum": 0,
                        "maximum": 10000000,
                        "type": "integer",
                        "description": "Only save books with at least this many Goodreads ratings."
                    },
                    "publishYearMin": {
                        "title": "Published year from",
                        "minimum": 0,
                        "maximum": 3000,
                        "type": "integer",
                        "description": "Only save books first published in or after this year when Goodreads exposes a year."
                    },
                    "publishYearMax": {
                        "title": "Published year to",
                        "minimum": 0,
                        "maximum": 3000,
                        "type": "integer",
                        "description": "Only save books first published in or before this year when Goodreads exposes a year."
                    },
                    "language": {
                        "title": "Language contains",
                        "type": "string",
                        "description": "Only save books whose Goodreads language field contains this text, such as English or en."
                    },
                    "containsGenre": {
                        "title": "Genre contains",
                        "type": "string",
                        "description": "Only save books with at least one genre containing this text."
                    },
                    "containsAuthor": {
                        "title": "Author contains",
                        "type": "string",
                        "description": "Only save books with at least one author name containing this text."
                    },
                    "deduplicateBooks": {
                        "title": "Deduplicate books",
                        "type": "boolean",
                        "description": "Save each Goodreads book once even if it appears in multiple submitted searches or URLs.",
                        "default": true
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
