# Amazon Best Sellers Scraper (`mlg14/amazon-bestsellers-scraper`) Actor

Scrape Amazon.in category rankings with product names, prices, images, ratings, review counts, and category links. Follow subcategories and export ranked products.

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

## Pricing

$1.00 / 1,000 results

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?

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

Scrape Amazon.in bestseller rankings and hot new release charts by category URL. Export Amazon India product rankings to JSON, CSV, or spreadsheet format with position, product name, price, image, rating, review count, and a stable product link. This actor is a practical Amazon India category data source for recurring research when a direct public ranking API is unavailable.

Each output row describes one product in one category at the time of the run. A product can appear in more than one category, and those appearances are separate rows because the rank and category context are different. The actor reads public ranking pages and does not require a shopper account or product detail page requests.

### What data can you extract from Amazon.in?

| Field | Description | Example |
| --- | --- | --- |
| `position` | Displayed rank within the category chart | `1` |
| `category` | Heading of the category chart | `Bestsellers in Electronics` |
| `categoryUrl` | Category page associated with this rank | `https://www.amazon.in/gp/bestsellers/electronics/` |
| `chartType` | Type of ranking chart | `Best Sellers` |
| `asin` | Product identifier shown in the chart card | `B0DDHM6D3L` |
| `name` | Product title shown in the chart card | `Conch Theta C in Ear Type C Wired Earphones...` |
| `price` | Displayed numeric price; null when absent | `311` |
| `currency` | `INR` for a displayed rupee price; otherwise null | `INR` |
| `numberOfOffers` | Offer count when the card displays one | `null` |
| `url` | Stable product page link | `https://www.amazon.in/dp/B0DDHM6D3L` |
| `thumbnail` | Product image URL from the category card | `https://images-eu.ssl-images-amazon.com/images/I/51GGwjwSr0L._AC_UL300_SR300,200_.jpg` |
| `rating` | Average star rating displayed on the card | `4.1` |
| `reviewCount` | Number of ratings displayed on the card | `13166` |

The values reflect the page at collection time. Price, rank, rating, and count can change between runs. `numberOfOffers` is kept as a stable field for downstream tables, but category cards generally do not display an offer count, so its usual value is null. A null price means the category card did not provide a usable rupee price; it does not mean the product is free. No price is inferred from another product or an earlier run.

### How to scrape Amazon Best Sellers

1. Open an Amazon.in Best Sellers category, such as Electronics, and copy the full category URL. A Hot New Releases category URL can also be used.
2. Paste one or more URLs into `categoryUrls`. Use department or subcategory URLs according to the range of products you need.
3. Choose `depthOfCrawl`. Keep it at `1` for only the supplied categories, or use `2` to follow the immediate subcategories linked on those pages. Set `maxItemsPerStartUrl` and `maxItems` to bound the result count.
4. Run the actor. The dataset contains one row per visible ranked product. Download the results as JSON, CSV, or a spreadsheet file, or read the dataset through its API endpoint.

For a quick first run, use the prefilled Electronics category with a total cap of 100. A focused subcategory URL often gives a cleaner comparison set than a broad department. For repeated monitoring, save the exact input so future runs refer to the same categories and caps.

### Input

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `categoryUrls` | Array of URLs | Electronics Best Sellers | Public Amazon.in ranking category pages to visit. At least one URL is required. |
| `maxItemsPerStartUrl` | Integer | `100` | Maximum rows from each visited category. `0` means collect every detailed card available on its public pages. |
| `depthOfCrawl` | Integer | `1` | `1` visits supplied categories; `2` follows their immediate subcategories; `3` adds another linked level. |
| `maxItems` | Integer | `100` | Overall dataset cap across all categories. `0` removes this cap. |
| `proxyConfiguration` | Object | Platform proxy | Optional network routing configuration. The default is suitable for ordinary runs. |

A realistic input for a department and its immediate subcategories is:

```json
{
  "categoryUrls": [
    "https://www.amazon.in/gp/bestsellers/electronics/"
  ],
  "maxItemsPerStartUrl": 100,
  "depthOfCrawl": 2,
  "maxItems": 80
}
```

That input was used for the final validation run. It returned 80 rows: the visible products on the Electronics chart, followed by products from a linked subcategory until the overall cap was reached. To compare several departments, supply several URLs in the array. The actor visits them in input order, then follows linked subcategories in discovery order. Once `maxItems` is reached, later categories are not visited. Set a larger cap if every supplied category must be covered.

`maxItemsPerStartUrl` applies to every visited category page, including discovered subcategories. It is a ceiling, not a promise that the site will show that many detailed products. A value of `100` may still return fewer rows from a category. `maxItems` is a separate ceiling on the whole dataset. If a run stops early because the platform budget is reached, the rows already delivered remain in the dataset.

### Output example

This is one row from the validated Electronics run. The product title is excerpted here for readability; the dataset contains the full title.

```json
{
  "position": 1,
  "category": "Bestsellers in Electronics",
  "categoryUrl": "https://www.amazon.in/gp/bestsellers/electronics/",
  "chartType": "Best Sellers",
  "asin": "B0DDHM6D3L",
  "name": "Conch Theta C in Ear Type C Wired Earphones...",
  "price": 311,
  "currency": "INR",
  "numberOfOffers": null,
  "url": "https://www.amazon.in/dp/B0DDHM6D3L",
  "thumbnail": "https://images-eu.ssl-images-amazon.com/images/I/51GGwjwSr0L._AC_UL300_SR300,200_.jpg",
  "rating": 4.1,
  "reviewCount": 13166
}
```

A category's position is its on-page rank, not the row number in a combined dataset. For example, the second page can begin at position 51 even though fewer than 50 detailed product cards were delivered from the first page. Keep `position` and `categoryUrl` together when comparing results. The `asin` identifies a product across categories, while the category fields identify where its rank was observed.

### Use cases

- **Category monitoring:** Record the visible leaders in a department every day and compare positions for the same product identifier over time. Save the run date in your own pipeline because the output describes a point-in-time chart.
- **Assortment research:** Compare bestseller names and product links across Electronics subcategories to see which products recur in related departments. A repeated product can have a different position in each category.
- **Price observation:** Compare displayed category-card prices in rupees across products or across scheduled runs. Filter out null prices instead of treating them as zero.
- **Review context:** Use the rating and count fields to distinguish highly ranked products with a large rating base from newer or less reviewed entries. These figures are page displays, not independently verified review data.
- **Launch tracking:** Collect Hot New Releases category pages to observe which products appear and how their positions change. Expect more missing price values on these charts than on the tested Electronics bestseller chart.
- **Catalog joining:** Use `asin` and the stable product URL to join chart observations with an existing catalog. Retain `categoryUrl` and `position` as the context of each observation.

### How much does it cost to scrape Amazon.in rankings?

The current result charge is **$1.00 per 1,000 delivered rows**, or **$0.001 per row**. The charge follows delivered dataset rows, so setting a cap controls the maximum number of result charges. The final validation run delivered 80 rows, which corresponds to $0.08 in result charges. A 500-row run would correspond to $0.50, and a 1,000-row run to $1.00. These examples describe result charges at the current rate; check the run screen for the current price before starting a large collection.

Category depth affects how quickly a run reaches its cap. With `depthOfCrawl` set to `1`, a single category has at most two linked ranking pages to visit. With depth `2` or `3`, each additional linked category can contribute its own set of rows. A broad department may therefore reach `maxItems` before all discovered subcategories are visited. Start with one department and a modest cap, inspect the category spread, and then increase the cap or narrow the starting URLs for the coverage you need.

Pricing is per result, not per input URL or request. Rows from separate categories are separate results even if they share an `asin`, because they represent distinct category ranks. An empty page produces no product rows. The actor stops when the overall cap or the run's available event budget is reached.

### Tips for best results

Start from a concrete category URL rather than a product page or a search results page. The actor recognizes Amazon.in ranking category paths; it does not turn arbitrary product or keyword URLs into ranking categories. For a focused dataset, begin with an exact subcategory and leave depth at `1`. For discovery, begin with a department URL and set depth to `2`. Depth `3` can expand the number of pages substantially, so pair it with a deliberate total cap.

Use multiple starting URLs when you already know the categories of interest. A direct URL gives you more control over coverage than depending on the order of a department's linked subcategories. URLs are normalized to remove tracking references, and a category is visited once per run. Products are kept separately when they belong to different categories, so do not deduplicate solely by product identifier if category rank matters to your analysis.

Run comparisons at similar times if you monitor ranks, because charts and prices change. Store the collection date alongside exported rows in your own system. For price work, use `currency` and exclude null price values. For review analysis, distinguish a null rating or count from zero; null means the field was not visible on the card. The output is a chart snapshot, not a full product detail record.

### Limits

Amazon.in ranking pages observed during development listed up to 100 ranks over two pages, but each page rendered only 30 detailed product cards. The validated Electronics category yielded 60 detailed rows from its two pages. The embedded page data included identifiers and ranks for additional positions without the corresponding names, prices, and images. This actor emits complete card records only; it does not invent product details for metadata-only positions. Site layouts and visible counts can change.

The Electronics bestseller validation returned 80 rows across a department and a linked subcategory. Required rank, category, identifier, title, link, and image fields filled every row. Price and currency filled 97.5% of rows in that run. A separate Hot New Releases check returned 60 rows, but price and currency filled only 55%, so it did not meet the stricter bestseller price threshold. Some alternate ranking chart pages also returned no product cards during source checks. The supported, best-verified workflow is a Best Sellers category URL.

The actor reads category cards and does not fetch each product detail page. Consequently, offer count is usually null, and fields such as seller, stock, variations, delivery location, full specifications, and historical price are outside this dataset. The displayed price can vary by visitor context or be absent. Regional availability, page experiments, and temporary blocks may change the output. If a category fails, the run records the failure and continues with other categories; it fails overall if no products are found.

### Programmatic use

The input and output are suitable for a scheduled workflow. For example, a request can say, “Collect the Electronics bestseller chart and its immediate subcategories, stop at 80 rows, and return each product's rank, identifier, price, and rating.” Another request can say, “Collect this Hot New Releases category once a day and flag products whose chart position improved; ignore rows with no displayed price.” These instructions map directly to the URL, depth, and result-cap fields above.

For automated comparisons, persist the dataset rows after each run and join by `asin` plus `categoryUrl`. Compare `position` across dates only within the same category and chart type. Treat a missing row as “not observed in the delivered set,” since caps and visible-card limits can prevent a product from appearing even when it is on a wider site ranking.

### FAQ

#### Is it legal to collect these rankings?

The actor reads publicly visible category pages. Your use of the data should respect the site's terms, applicable law, and privacy requirements. Do not use public ranking data to infer personal information or collect data behind a login.

#### Do I need to configure a proxy?

The default network setting is designed for these public pages. Temporary blocks or routing errors can still occur. The actor retries requests and can change routing when a page is blocked. Leave the default setting unless you have a specific routing requirement.

#### How fast is a run?

The time depends on category count, depth, network response, and whether any request needs a retry. The validated single-department run with one subcategory reached 80 rows in a hosted run. Larger depth and multiple starting URLs take longer because each category can require two page requests.

#### Can I schedule runs and monitor changes?

Yes. Save the input and schedule repeated runs. Export or retain each dataset with its run time, then compare `position` for the same `asin`, `categoryUrl`, and `chartType`. A scheduled run reflects the page at that time; it does not reconstruct ranks between runs.

#### Can I export to a spreadsheet?

Yes. Download the dataset as CSV or a spreadsheet format, or read its dataset endpoint into your existing reporting process. Numeric prices, ranks, ratings, and counts are separate fields, which makes sorting and filtering straightforward.

#### Why is a price, rating, or offer count empty?

A field is null when the category card did not show a usable value. This is common for `numberOfOffers`, and prices were frequently absent in the tested Hot New Releases chart. The actor does not substitute a guessed value or a price from another time.

#### Why did I receive fewer than 100 products from one category?

The page may expose ranks up to 100 while rendering fewer detailed cards. In the tested Electronics bestseller category, two pages provided 60 detailed cards. Your per-category or total cap can lower that number further. Some categories may have fewer products or no cards at all.

### Integrations

Use the dataset endpoint to pass ranked products into a database, a reporting pipeline, a webhook, or a spreadsheet. A saved input can run on a schedule, and a completion notification can trigger a downstream comparison. Keep the run time and category URL alongside each row so that later analysis can distinguish changing ranks from different source categories or incomplete collection.

### Support

Open an issue on the Issues tab; we reply within 24h and add fields on request. Include the category URL, run time, and the field or rank that needs attention. A short example of the expected page data helps reproduce changes in the site's layout.

# Actor input Schema

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

One or more public Amazon.in Best Sellers or Hot New Releases category URLs. Use a department or a specific subcategory page.

## `maxItemsPerStartUrl` (type: `integer`):

Maximum products from each visited category. Zero means all visible products. Amazon.in currently displays up to 100 ranks across two pages, though fewer detailed cards may be rendered.

## `depthOfCrawl` (type: `integer`):

One collects only the supplied categories. Two also follows their immediate subcategories. Three follows one more level.

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

Hard cap on dataset rows across all categories. Zero removes the total cap; the per-category limit still applies.

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

Network routing for public category pages. The default configuration uses platform proxy routing.

## Actor input object example

```json
{
  "categoryUrls": [
    "https://www.amazon.in/gp/bestsellers/electronics/"
  ],
  "maxItemsPerStartUrl": 100,
  "depthOfCrawl": 1,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Scraped product rows in the default dataset.

# 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.in/gp/bestsellers/electronics/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mlg14/amazon-bestsellers-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 = { "categoryUrls": ["https://www.amazon.in/gp/bestsellers/electronics/"] }

# Run the Actor and wait for it to finish
run = client.actor("mlg14/amazon-bestsellers-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 '{
  "categoryUrls": [
    "https://www.amazon.in/gp/bestsellers/electronics/"
  ]
}' |
apify call mlg14/amazon-bestsellers-scraper --silent --output-dataset

```

## MCP server setup

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