# Amazon Kindle Scraper (`w3crawler/amazon-kindle-scraper`) Actor

Scrapes Amazon Kindle ebook listings including pricing, ratings, and metadata.

- **URL**: https://apify.com/w3crawler/amazon-kindle-scraper.md
- **Developed by:** [w3crawler](https://apify.com/w3crawler) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 kindle books

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Amazon Kindle Scraper

This existing local implementation is the maintained equivalent for the assigned **Kindle Book Deals Scraper** row (CSV rank 1569, store slug `lucascode/kindle-book-deals-scraper`). It was reused rather than creating a duplicate folder.

Search the public Amazon Kindle Store and return structured ebook listing records. The actor uses serialized direct HTTPS requests and a linkedom HTML parser. It does not use a browser, stealth fingerprinting, retries, proxies, CAPTCHA solving, sign-in, or paywalled content. If Amazon returns an access challenge or denial, the run stops and reports status and counts in `OUTPUT_SUMMARY`; failure details stay in the run logs.

### Extracted fields

Listing records can include:

- ASIN, title, name, author, authors, and public author URLs
- Rating, rating-count text, normalized review count, publication date, price, price text, and currency
- Kindle Edition format, seller, availability, Kindle Unlimited eligibility, sponsored status, badges, and series text
- Stable product/canonical URLs, request/search-page URL, cover image URLs, and bounded source-card text
- Optional public detail metadata: description, publisher, publication date, language, file size, print length, ISBN-13, bestseller ranks, and additional image URLs
- Common evidence fields: direct transport, HTTP status, access/fetch status, field coverage, data-quality counts, and stable record IDs

The dataset contains source-backed Kindle listing rows only. Empty results complete with `status: SUCCEEDED` and `dataStatus: NO_RESULTS`; access blocks and genuine request or extraction failures produce `status: FAILED` and `dataStatus: FAILED` when no source rows were saved. Failure details stay in the run logs; no diagnostic dataset rows are written.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| keyword | string, required | — | Book title, author, topic, or genre |
| country | string | us | Amazon marketplace: us, uk/gb, de, fr, it, in, ca, au, es, jp, or br |
| locale | string | marketplace locale | BCP 47 locale used for `Accept-Language` |
| maxItems | integer | 40 | Maximum listing records, from 1 to 500 |
| startPage | integer | 1 | 1-based search page to start from |
| maxPages | integer | 0 | Page limit; 0 derives a bounded limit from `maxItems` |
| sortBy | string | relevance | relevance, rating, newest, priceLowToHigh, priceHighToLow, or bestsellers |
| kindleUnlimitedOnly | boolean | false | Keep only cards marked Kindle Unlimited |
| minRating | number | — | Optional local minimum rating from 0 to 5 |
| dateRange | string | — | last30Days, last90Days, or comingSoon |
| minPrice / maxPrice | number | — | Optional displayed-price bounds |
| excludeSponsored | boolean | false | Drop cards visibly marked Sponsored |
| includeDetails | boolean | false | Fetch public product pages for detail metadata |
| maxDetailItems | integer | 10 | Maximum detail-page attempts |
| includeMedia | boolean | true | Include cover and responsive image URLs |
| dedupeBy | string | asin | asin, title, or none |
| requestDelayMs | integer | 1000 | Delay between serialized page and detail requests |
| requestTimeoutSecs | integer | 180 | Maximum direct HTTP request time |

The legacy `pageRenderWaitMs`, `maxConcurrency`, `maxRequestRetries`, `navigationTimeoutSecs`, and `proxyConfiguration` fields remain accepted for input compatibility, but are ignored by the direct-only runner. The older Amazon sort aliases are also accepted.

#### Example input

```json
{
  "keyword": "science fiction",
  "country": "us",
  "maxItems": 20,
  "sortBy": "rating",
  "kindleUnlimitedOnly": false,
  "includeDetails": true,
  "maxDetailItems": 5,
  "requestDelayMs": 1200
}
```

### Output

Listing records include `position`, `asin`, `title`, `author`, `rating`, `reviewCount`, `price`, `currency`, `format`, `isKindleUnlimited`, `sourceUrl`, `imageUrl`, `keyword`, `country`, and `scrapedAt`, plus optional public detail fields. Source labels, transport/access flags, `fieldCoverage`, `dataQuality`, and run metadata are removed from rows. See `.actor/dataset_schema.json` for the full contract.

Every run writes `OUTPUT_SUMMARY` to the declared key-value store. It includes request/page counts, candidate/filter/duplicate counts, detail outcomes, data availability, proxy usage (`false`), status, and failure counts. `successfulItems` counts source-backed dataset rows; `diagnosticCount` counts operational issues and never dataset rows; `invalidSourceRecordCount` counts candidates rejected before a Dataset write for missing listing identity fields.

### Access and reliability

Amazon may vary markup, prices, availability, localization, and anti-bot behavior. Public search and detail pages may return a CAPTCHA, Akamai interstitial (`bm-verify`/`_sec/verify`), or other access challenge; the actor reports that state instead of attempting to bypass it. Requests are serialized and use a transparent actor user agent. A blocked request is fail-closed and is not retried.

### Local development

Create local input at `storage/key_value_stores/default/INPUT.json`, then run:

```
apify run
```

Useful checks:

```
apify validate-schema
npm test
node validate-datasets.js
```

Local run output stays under `storage/` and is not uploaded automatically.

Run summaries include the required `status`, `runStatus`, and `dataStatus` fields. `status` and `runStatus` are `SUCCEEDED` when source-backed rows were saved or a run completed cleanly with no matches; they are `FAILED` only when a real failure occurs before any rows are saved. `dataStatus` is `COMPLETE`, `PARTIAL`, `NO_RESULTS`, or `FAILED`. Failure details stay in the run logs; key-value summaries retain counts only.

# Changelog

This Actor's version history is a separate document: https://apify.com/w3crawler/amazon-kindle-scraper/changelog.md

# Actor input Schema

## `keyword` (type: `string`):

Book title, author, topic, or genre to search for.

## `country` (type: `string`):

Amazon marketplace code used for the search domain.

## `locale` (type: `string`):

BCP 47 locale used for the direct request Accept-Language header.

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

Maximum Kindle listing records to return. Diagnostic records do not count toward this limit.

## `startPage` (type: `integer`):

1-based Amazon search-results page to start from.

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

Maximum search-results pages to visit. Use 0 to derive a bounded limit from maxItems.

## `sortBy` (type: `string`):

Amazon sort order for search results.

## `kindleUnlimitedOnly` (type: `boolean`):

Keep only listings visibly marked as Kindle Unlimited eligible.

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

Optional minimum star rating from 0 to 5. The result is also checked locally after extraction.

## `dateRange` (type: `string`):

Optional Amazon publication-date refinement.

## `minPrice` (type: `number`):

Optional minimum displayed Kindle price in the selected marketplace currency.

## `maxPrice` (type: `number`):

Optional maximum displayed Kindle price in the selected marketplace currency.

## `excludeSponsored` (type: `boolean`):

Exclude result cards that Amazon marks as sponsored.

## `includeDetails` (type: `boolean`):

Open public Kindle product pages for optional metadata such as description, publisher, language, and ISBN.

## `maxDetailItems` (type: `integer`):

Maximum listing records for which public detail pages are attempted.

## `includeMedia` (type: `boolean`):

Include cover image URLs and responsive image candidates.

## `dedupeBy` (type: `string`):

Duplicate handling within and across paginated result pages.

## `requestDelayMs` (type: `integer`):

Delay between serialized direct search requests and detail-page requests.

## `pageRenderWaitMs` (type: `integer`):

Compatibility field retained for older inputs; ignored by the direct HTML runner.

## `maxConcurrency` (type: `integer`):

Compatibility field retained for older inputs; requests are always serialized.

## `maxRequestRetries` (type: `integer`):

Compatibility field retained for older inputs; the direct runner performs no automatic retries.

## `requestTimeoutSecs` (type: `integer`):

Maximum direct HTTP request time in seconds.

## `navigationTimeoutSecs` (type: `integer`):

Compatibility timeout alias used when the direct request timeout is absent.

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

Compatibility field retained for older inputs; this actor never configures or uses a proxy.

## Actor input object example

```json
{
  "keyword": "kindle books",
  "country": "us",
  "locale": "en-US",
  "maxItems": 40,
  "startPage": 1,
  "maxPages": 0,
  "sortBy": "relevance",
  "kindleUnlimitedOnly": false,
  "excludeSponsored": false,
  "includeDetails": false,
  "maxDetailItems": 10,
  "includeMedia": true,
  "dedupeBy": "asin",
  "requestDelayMs": 1000,
  "pageRenderWaitMs": 1500,
  "maxConcurrency": 1,
  "maxRequestRetries": 3,
  "requestTimeoutSecs": 180,
  "navigationTimeoutSecs": 90,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing source-backed Kindle listing records only.

# 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 = {
    "keyword": "kindle books",
    "country": "us",
    "locale": "en-US",
    "maxItems": 40,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/amazon-kindle-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 = {
    "keyword": "kindle books",
    "country": "us",
    "locale": "en-US",
    "maxItems": 40,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/amazon-kindle-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 '{
  "keyword": "kindle books",
  "country": "us",
  "locale": "en-US",
  "maxItems": 40,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call w3crawler/amazon-kindle-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,w3crawler/amazon-kindle-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/bHvIAizjb0k5WZAb6/builds/hcpmaEFtw3LNk3pXR/openapi.json
