# Amazon Best Sellers Scraper (rank, price, rating, monitor) (`datahamster/amazon-bestsellers`) Actor

Amazon Best Sellers, New Releases and Movers & Shakers scraper: one row per ranked product with Amazon's rank, price in the marketplace currency, rating and review count, on ten marketplaces. Monitor mode alerts on rank moves and price changes. You pay only for rows returned.

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

## Pricing

from $1.60 / 1,000 result items

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

## Amazon Best Sellers Scraper (rank, price, rating, monitor)

One row per ranked product from an Amazon category list — **Best Sellers**, **New Releases** or **Movers &
Shakers** — on ten marketplaces, with Amazon's own rank, the price in that marketplace's currency, the rating
and the review count. Monitor mode turns the same input into a daily alert on rank moves and new entries.

### What you get

One row per product: `id` (`<marketplace>:<ASIN>`), `asin`, `url`, `marketplace`, `listType`, `category`,
`categoryUrl`, `rank`, `title`, `price`, `priceText`, `currency`, `rating`, `ratingCount`, `imageUrl`,
`isPrime`, `salesRankChange`, `query`, `page`, `scrapedAt`.

`rank` is Amazon's own rank on the list, read from the ranking data the page carries — not the row's position
in your dataset, so a row keeps its true rank no matter how the dataset is sorted or filtered.

### Example output

```json
{
  "id": "com:B08JHCVHTY",
  "asin": "B08JHCVHTY",
  "url": "https://www.amazon.com/dp/B08JHCVHTY",
  "marketplace": "com",
  "listType": "bestsellers",
  "category": "Electronics",
  "categoryUrl": "https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics",
  "rank": 1,
  "title": "blink plus plan with monthly auto-renewal",
  "price": 11.99,
  "priceText": "$11.99",
  "currency": "USD",
  "rating": 4.4,
  "ratingCount": 280228,
  "imageUrl": "https://images-na.ssl-images-amazon.com/images/I/31YHGbJsldL._AC_UL300_SR300,200_.png",
  "page": 1
}
```

| `rank` | `title` | `price` | `rating` | `ratingCount` |
|---|---|---|---|---|
| 1 | blink plus plan with monthly auto-renewal | 11.99 USD | 4.4 | 280228 |
| 51 | 3 Pairs Replacement Ear Tips for AirPods Pro | 6.99 USD | 4.3 | 40644 |
| 1 (amazon.de) | NEW'C for iPhone 17, Tempered Glass | 7.99 EUR | 4.3 | 292804 |

### Use cases

- **Category tracking.** Run it daily on your categories and keep a rank history: what entered the top 100,
  what fell out, what changed price.
- **Competitor and niche research.** Rank, price, rating and review count side by side is enough to size a
  niche before you source a product.
- **New-product radar.** `listType: new-releases` is the list of what Amazon just started selling in a
  category — in monitor mode you get an alert the day a product appears.
- **Cross-marketplace price gaps.** The same list on `.com` and `.de` returns each marketplace's own currency,
  because the exit country is pinned to the marketplace.

### Input

| Field | Meaning | Default |
|---|---|---|
| `categoryUrls` | Best Sellers / New Releases / Movers & Shakers URLs, one per line. Any marketplace, any depth of sub-category | empty |
| `categories` | Category slugs (`electronics`, `books`, `kitchen`) used with `marketplace` and `listType` | empty |
| `marketplace` | `com`, `de`, `co.uk`, `fr`, `it`, `es`, `ca`, `co.jp`, `in`, `com.au` | `com` |
| `listType` | `bestsellers`, `new-releases` or `movers-and-shakers` | `bestsellers` |
| `maxPagesPerList` | Pages per list, 1-10 (Amazon has two per list) | `2` |
| `maxItems` | Stop after this many rows | `100` |
| `mode` | `scrape`, or `monitor` for only new/changed rows | `scrape` |
| `monitorStateId`, `webhookUrl`, `telegramBotToken`, `telegramChatId` | Monitor-mode state key and alert targets | empty |

Give either `categoryUrls` or `categories` — a URL names its own marketplace and list type, so the two other
fields are ignored for it.

**Monitor mode** keys each product on `<marketplace>:<ASIN>` and compares `rank` and `price`, so you are
alerted when a product enters the list, moves rank, or changes price — and charged only for those rows.

### Pricing

| Event | Price |
|---|---|
| result | $0.002 per product ($2 per 1,000) |
| monitor-check | $0.006 per monitor run |
| change | $0.002 per new or changed product |

You are charged only for rows actually pushed. A refused request pushes nothing and charges nothing.

The actor runs through Apify's **residential proxy with the exit in the marketplace's own country**. That is
what the proxy is for here: Amazon quotes prices and availability by exit location, so an exit in a random
country returns a foreign currency or no price at all. That proxy traffic is platform usage billed to your
account at Apify's own rate; a list page measured **450-470 KB** on 2026-09-17.

### Limits — read this before you buy

- **30 products per page.** Amazon ranks 50 products per page but server-renders the first 30 and loads the
  rest from its own browser-side API. This actor returns the rendered 30, so the default two pages give you
  ranks **1-30 and 51-80** of a list, and `maxPagesPerList: 1` gives ranks 1-30. Every row carries its true
  rank, so the gap is visible rather than silently renumbered.
- **Movers & Shakers is empty at the source right now.** Checked on 2026-09-17 on `.com`, `.de` and `.co.uk`:
  every Movers & Shakers URL answers "there are no movers and shakers available in this category". The list
  type is implemented and `salesRankChange` is filled the moment Amazon serves the data again; until then a
  Movers & Shakers run returns nothing (and charges nothing). Use `bestsellers` or `new-releases`.
- **Category slugs differ per marketplace.** `electronics` is a `.com` slug; on `.de` the same list is
  `ce-de`. The safe way is to paste the URL from your browser into `categoryUrls`. An unknown slug is
  reported as invalid input, not as an empty result.
- **`isPrime` is usually empty**, because the list cards mostly carry no Prime badge. `price` is empty for the
  few cards Amazon renders without one.
- **Prices are the list-card price** in the marketplace's currency, not a per-variant or per-seller offer.
- **Ten marketplaces**, and only those ten: `.com`, `.de`, `.co.uk`, `.fr`, `.it`, `.es`, `.ca`, `.co.jp`,
  `.in`, `.com.au`. Each one's `robots.txt` was read before the host was enabled, and a URL on any other
  Amazon host is refused rather than fetched.
- No sub-category rows: the sub-category URLs found in the left rail are written to the run's
  `LIST_SUMMARY` record so you can feed them back as `categoryUrls`, but they are never pushed as rows.

### What is NOT collected

No personal data of any kind. Rows are product-level: no reviewer names, no review text, no customer
profiles, no seller contacts, no buyer data. The review pages linked from every card are never opened, and
the tracking tails Amazon puts in its own links (session ids, `ref=` tags) are stripped from every URL.

### FAQ

**Why does my dataset skip ranks 31-50?** See Limits: Amazon renders 30 of the 50 products a page ranks.

**Do I need my own proxy?** No. The actor uses Apify's residential proxy with the exit pinned to the
marketplace's country, which is what keeps prices in that marketplace's currency.

**Why did a run return nothing?** The `RUN_SUMMARY` record in the run's key-value store carries
`emptyReason`: `no_matches` (the list itself was empty — Movers & Shakers today), `invalid_input` (the slug
or URL does not exist on that marketplace) or `blocked` (Amazon answered with its robot check). A blocked run
never masquerades as an empty one.

**Can it follow sub-categories automatically?** Not in this version. The sub-category URLs are in the
`LIST_SUMMARY` record of every run; paste the ones you want into `categoryUrls`.

### Changelog

- 0.1: initial release — Best Sellers, New Releases and Movers & Shakers on ten marketplaces, rank from the
  page's own ranking data, per-marketplace currency, monitor mode on rank and price, robot checks reported as
  blocks instead of empty datasets.

***

If this actor saved you time, a short review on its Store page genuinely helps other people find it. Found a
bug or need a field that is missing? Open a ticket on the **Issues** tab.

# Actor input Schema

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

Stop after this many results (you are charged only for pushed items)

## `mode` (type: `string`):

scrape = full results; monitor = only new/changed items since the previous run of this task

## `monitorStateId` (type: `string`):

Optional state id when not running as a saved task (monitor mode)

## `webhookUrl` (type: `string`):

POST a change summary here in monitor mode

## `telegramBotToken` (type: `string`):

Optional: bot token for monitor-mode change summaries

## `telegramChatId` (type: `string`):

Optional: chat id that receives monitor-mode summaries

## `categoryUrls` (type: `array`):

Best Sellers, New Releases or Movers & Shakers URLs, one per line, e.g. "https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics". Any marketplace and any sub-category depth. A URL names its own marketplace and list type, so Marketplace and List type are ignored for it.

## `categories` (type: `array`):

Category slugs to build URLs from, one per line, e.g. "electronics", "books", "kitchen". Slugs differ per marketplace (Electronics is "electronics" on .com and "ce-de" on .de), so pasting the URL is safer. Used together with Marketplace and List type.

## `marketplace` (type: `string`):

Which Amazon marketplace the category slugs belong to. The proxy exit is pinned to that country, so prices come back in its currency. Example: de.

## `listType` (type: `string`):

Which list to read for the category slugs. Amazon currently answers every Movers & Shakers URL with an empty list (checked 2026-09-17 on .com, .de and .co.uk), so that option returns nothing until Amazon serves the data again.

## `maxPagesPerList` (type: `integer`):

How many pages to read per list. Amazon has two (ranks 1-100) and renders 30 products of each, so 2 pages return ranks 1-30 and 51-80. Range 1-10.

## Actor input object example

```json
{
  "maxItems": 100,
  "mode": "scrape",
  "categoryUrls": [
    "https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics"
  ],
  "marketplace": "com",
  "listType": "bestsellers",
  "maxPagesPerList": 2
}
```

# Actor output Schema

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

All pushed rows (dataset, JSON)

## `resultsTable` (type: `string`):

Dataset in the Console viewer

## `runSummary` (type: `string`):

RUN\_SUMMARY record

# 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 = {
    "categoryUrls": [
        "https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahamster/amazon-bestsellers").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 = { "categoryUrls": ["https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics"] }

# Run the Actor and wait for it to finish
run = client.actor("datahamster/amazon-bestsellers").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 '{
  "categoryUrls": [
    "https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics"
  ]
}' |
apify call datahamster/amazon-bestsellers --silent --output-dataset

```

## MCP server setup

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

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/c0MZernvSd9sGg7A6/builds/9hg2JmO4r5IwDgETH/openapi.json
