# Amazon Reviews Scraper with Coverage Report (`muhzuhaib/amazon-reviews-coverage-scraper`) Actor

Scrapes Amazon product reviews and tells you exactly how many you got, how many exist, and why it stopped. Charged per review delivered, so a run that returns nothing costs nothing.

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

## Pricing

$3.00 / 1,000 reviews

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Amazon Reviews Scraper with Coverage Report

Scrapes Amazon product reviews, and tells you exactly what you got.

Every run reports, per product, how many reviews Amazon has, how many came back, and the reason it stopped. You are charged per review delivered and for nothing else, so a run that comes back empty costs you nothing.

### Why this one

Amazon review scrapers are easy to start and hard to finish. The common failure is not an error message, it is a run that reports success, hands you 20 rows, and never mentions that the product has 146 reviews. You find out when the analysis is already built on top of the gap.

This scraper is built around removing that silence.

**Every product gets a coverage record.**

```json
{
  "asin": "B08N5WRWNW",
  "requestedReviews": 500,
  "retrievedReviews": 100,
  "reviewsWithTextOnAmazon": 317,
  "ratingsOnAmazon": 1482,
  "missingReviews": 217,
  "complete": false,
  "pagesRead": 10,
  "duplicatesDropped": 3,
  "stopReason": "amazon-pagination-limit",
  "stopReasonExplained": "Amazon stops paginating its reviews listing after 10 pages, for every caller"
}
```

The same summary goes on the run's status message, so you can see it without opening anything:

> 340 of 1,206 reviews from 4 products. 2 complete, 2 partial: 2 stopped because Amazon stops paginating its reviews listing after 10 pages, for every caller.

**You are only charged for reviews that reach your dataset.** There is no start fee. If Amazon blocks the run, or the ASIN is wrong, or the product has no reviews, the run costs nothing.

**Every URL you paste is scraped.** Each product gets its own review budget and its own coverage record, so a long first product cannot eat the allowance of the ones behind it, and one product being blocked does not truncate the rest.

### Two numbers that are not the same

Amazon publishes **ratings** and **reviews**, and they are different totals:

- **Ratings** counts every star given, including the many left with no written text.
- **Reviews** counts only the ones with text.

Only reviews with text exist as individual records anywhere on Amazon. Star-only ratings are counted in the histogram and are never published one by one, so **no scraper can return them** and any tool implying otherwise is measuring itself against a number it cannot reach. This actor reports both totals and measures its own shortfall against the reviews figure, which is the honest denominator.

### Amazon's ten-page limit, and how to get more anyway

Amazon's reviews listing stops after **10 pages of 10 reviews** for every caller. That is a hard ceiling of roughly 100 reviews per filter combination, and it is Amazon's, not this actor's. When a run hits it, the coverage record says `amazon-pagination-limit` rather than pretending the reviews ran out. When Amazon blocks the listing outright and only the product page is readable, it says `listing-blocked-product-page-only` instead.

The way past it is to run each filter separately, because Amazon applies the ten-page limit to each one on its own:

- Run once per star rating (`5 star only` through `1 star only`) for up to five times the reviews.
- Split further by `Most recent` and `Most helpful`.
- Split again by `Verified purchases only`.

The coverage record on each run tells you which slices are full and therefore worth splitting again.

### Input

| Field | What it does |
| --- | --- |
| `productUrls` | Amazon product or reviews URLs, any marketplace. Mix `amazon.com` and `amazon.co.uk` freely: the marketplace is read from each URL. |
| `asins` | Ten-character codes such as `B08N5WRWNW`, if pasting full URLs is inconvenient. |
| `domain` | Which marketplace the ASINs belong to. 21 marketplaces supported. URLs ignore this. |
| `maxReviewsPerProduct` | A budget **per product**, not for the run. |
| `sortBy` | Most recent, or most helpful. |
| `filterByStar` | All, a single star rating, or positive against critical. |
| `reviewerType` | All reviewers, or verified purchases only. |
| `mediaType` | All reviews, or only those with photos and video. |
| `formatType` | All variants of the product, or only the one you linked. |
| `language` | An Amazon locale code such as `en_US`. |
| `proxyConfiguration` | Residential by default, and strongly recommended. |

Bad entries are reported in the log rather than silently dropped, so a typo in one URL is visible instead of appearing as a product with no reviews.

### Output

One row per review:

| Field | |
| --- | --- |
| `asin`, `domain`, `productUrl` | Which product the review belongs to |
| `reviewId`, `reviewUrl` | Stable identifier and a direct link |
| `rating` | The star rating as a number, half stars included |
| `title`, `body` | The review as written, with Amazon's own interface stripped out. No trailing "Read more", no accessibility teaser, no star rating glued to the front of the title. Whitespace is cleaned up and paragraphs are kept |
| `publishedAt` | An ISO date, so it can be sorted and filtered |
| `dateText` | Amazon's original sentence, kept as written |
| `reviewedInCountry` | Which marketplace the reviewer wrote from |
| `author`, `authorProfileUrl` | The public display name Amazon shows on the review |
| `verifiedPurchase` | Whether Amazon marked it a verified purchase |
| `helpfulVotes` | Helpful count as a number |
| `variant` | The size, colour or format reviewed |
| `images` | Review photos, at full resolution rather than as thumbnails |
| `scrapedAt` | When this row was collected |

Coverage records go to a separate `coverage` dataset and to the `COVERAGE` key in the run's key-value store, so the main dataset stays clean for a CSV or Excel export.

### Limits, stated plainly, and measured

These are results from real runs on 2026-09-03, not estimates.

**Amazon blocks its paginated reviews listing from datacentre IP addresses.** It answers with an anti-bot interstitial that returns HTTP 200 and looks like a normal page. This actor detects it, retries on fresh sessions, and when the listing stays blocked it falls back to the reviews Amazon embeds in the product page itself. **On a free Apify plan, which has no residential proxy, expect roughly 8 to 15 reviews per product** and a coverage record saying `listing-blocked-product-page-only`. The largest measured run was four products and returned 34 reviews with every core field populated on every row. One of those four came back with nothing at all, its coverage record named the reason as `blocked`, and it was not charged for.

**A residential proxy is what unlocks the paginated listing.** Amazon treats residential addresses very differently from datacentre ones. That path has not yet been measured here, so this listing does not claim a number for it.

**Amazon's reviews listing stops after 10 pages of 10 reviews for every caller**, so around 100 per filter combination is the ceiling even when the listing is reachable. Split by star rating and by sort order to go past it.

**Star-only ratings cannot be returned by anything**, because Amazon does not publish them individually. See the section above.

**Only public review pages are read.** The reviewer's public display name and their review text, which is what Amazon itself shows on the page. No email addresses, no contact details, no attempt to identify anyone behind a display name.

**Whatever happens, the coverage record says which of these you hit**, and you are charged only for reviews that reached your dataset.

### Pricing

Charged per review written to your dataset. No monthly fee, no start fee, no charge for a run that returns nothing.

# Actor input Schema

## `productUrls` (type: `array`):

Amazon product or reviews URLs. Any marketplace, any of the /dp/, /gp/product/ or /product-reviews/ forms. The marketplace is read from each URL, so you can mix amazon.com and amazon.co.uk in one run.

## `asins` (type: `array`):

Ten-character Amazon codes such as B08N5WRWNW, if you would rather not paste full URLs. These use the marketplace set below.

## `domain` (type: `string`):

Which Amazon marketplace the ASINs above belong to. URLs carry their own marketplace and ignore this.

## `maxReviewsPerProduct` (type: `integer`):

A budget per product, not for the whole run, so one product cannot eat another's allowance. Amazon's own reviews listing stops after 10 pages of 10, so 100 is the realistic ceiling per filter combination. Ask for more and the coverage record will tell you where it stopped.

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

Most recent gives you a time series. Most helpful gives you the reviews Amazon promotes.

## `filterByStar` (type: `string`):

Amazon applies the 10-page limit to each filter separately, so running the five star filters one at a time returns more reviews in total than running with no filter at all. The coverage record makes that visible.

## `reviewerType` (type: `string`):

Whether to include every reviewer, or only those Amazon marks as verified purchases.

## `mediaType` (type: `string`):

Whether to include every review, or only those with a photo or video attached.

## `formatType` (type: `string`):

Whether to include reviews written for other variants of the same product, such as a different size or colour.

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

An Amazon locale code such as en\_US or de\_DE. Leave empty for the marketplace default.

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

How many pages to fetch at once. Higher is faster and more likely to be blocked. Values outside 1 to 50 are clamped rather than rejected.

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

Residential proxy is the default and is strongly recommended. Amazon answers unproxied and datacentre requests for its reviews listing with a sign-in page.

## `debugSnapshots` (type: `boolean`):

When a page returns no reviews, save its raw HTML to the key-value store so the cause can be diagnosed. Off by default; turn it on only when reporting a problem.

## Actor input object example

```json
{
  "productUrls": [
    {
      "url": "https://www.amazon.com/dp/B08N5WRWNW"
    }
  ],
  "domain": "amazon.com",
  "maxReviewsPerProduct": 100,
  "sortBy": "recent",
  "filterByStar": "all_stars",
  "reviewerType": "all_reviews",
  "mediaType": "all_contents",
  "formatType": "all_formats",
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "debugSnapshots": false
}
```

# Actor output Schema

## `reviews` (type: `string`):

Every review delivered by this run, one row each, with ASIN, rating, title, body, date, reviewer, verified-purchase flag, helpful votes, variant, country, photos and a link back to the review.

## `coverage` (type: `string`):

One record per product: reviews retrieved, reviews Amazon says exist, pages walked, duplicates skipped, and the reason the run stopped. Written whether the run succeeded or not.

# 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 = {
    "productUrls": [
        {
            "url": "https://www.amazon.com/dp/B08N5WRWNW"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhzuhaib/amazon-reviews-coverage-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 = { "productUrls": [{ "url": "https://www.amazon.com/dp/B08N5WRWNW" }] }

# Run the Actor and wait for it to finish
run = client.actor("muhzuhaib/amazon-reviews-coverage-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 '{
  "productUrls": [
    {
      "url": "https://www.amazon.com/dp/B08N5WRWNW"
    }
  ]
}' |
apify call muhzuhaib/amazon-reviews-coverage-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhzuhaib/amazon-reviews-coverage-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/Mh3fVyrgnC96nYyr9/builds/WVm96jW4qGyBqGAkO/openapi.json
