# Amazon Sales Scraper (`mlg14/amazon-sales-scraper`) Actor

Scrape Amazon product search results and product pages with prices, reviews, rank, purchase-count badges, and conservative monthly sales and revenue floors.

- **URL**: https://apify.com/mlg14/amazon-sales-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

$4.44 / 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 Sales Scraper

Scrape Amazon product search results and product pages to compare prices, reviews, category rank, and visible purchase activity. Export Amazon product data to CSV or JSON for catalog research, price tracking, and a practical Amazon product data feed without maintaining your own collection infrastructure.

The actor accepts search keywords, product URLs, or ASINs. For products with a visible “bought in past month” badge, it reports a conservative monthly sales floor and a revenue floor calculated from the displayed price. Those values are **lower bounds**, not exact sales or a claim about a seller’s private order data. A run with the `garlic press` keyword collected 30 products with full detail pages; 29 had a purchase-count badge at the time of the run.

### What data can you extract from Amazon?

Each dataset item represents one product. Field names use camelCase. Search results provide the core catalog and purchase signals; enabling full details adds the product page fields that are visible for that item. The actor leaves a field empty when Amazon does not show it or when a product page cannot be retrieved after retries.

| Field | Description | Example |
| --- | --- | --- |
| `asin` | Product identifier | `B098WNQ44M` |
| `url` | Canonical product link | `https://www.amazon.com/dp/B098WNQ44M` |
| `marketplace` | Marketplace suffix | `com` |
| `title` | Product title | `Kitessensu High Effective Garlic Press...` |
| `brand` | Displayed brand or store name | `KITESSENSU` |
| `price` | Current displayed price, including currency | `$8.99` |
| `listPrice` | Displayed list or crossed-out price | `$12.99` when shown |
| `discountPercent` | Discount computed from those two prices | `31` when both prices exist |
| `coupon` | Visible coupon message | A displayed coupon, when present |
| `rating` | Average rating out of five | `4.6` |
| `reviewCount` | Displayed review count | `16105` |
| `reviewDistribution` | Percentages for one through five stars | `{"5StarPct":77}` |
| `bestSellersRank` | Visible category rank entries | `[{"rank":913,"category":"Kitchen & Dining"}]` |
| `boughtInPastMonth` | Purchase-count bucket shown by the site | `4K+` |
| `estimatedMonthlySales` | Minimum monthly units implied by that bucket | `4000` |
| `estimatedMonthlyRevenue` | Sales floor multiplied by current price | `$35,960.00` |
| `salesEstimateMethod` | Source of the calculation | `boughtBadgeFloor` |
| `categories` | Breadcrumb category path | `Home & Kitchen`, `Kitchen & Dining` |
| `features` | Product bullet points | `Built to Last...` |
| `description` | Visible long description | Text when available |
| `specs` | Product detail label and value pairs | `{"Material Type":"Zinc"}` |
| `variants` | Visible option ASINs and labels | `{"asin":"B098WFBBJZ","dimensions":{"Color":"..."}}` |
| `images` | Product image links | Image URLs |
| `availability` | Visible availability message | `In Stock` |
| `stockLeft` | Quantity from an “Only N left” message | `3` when shown |
| `soldBy` | Merchant shown on the detail page | Merchant name |
| `shipsFrom` | Shipping party shown on the detail page | `Amazon` |
| `isPrime` | Whether a visible product badge is found | `true` or `false` |
| `isFba` | Whether the merchant link identifies site fulfillment | `true` or `false` |
| `badges` | Visible product labels | `Amazon's Choice` |
| `relatedAsins` | Other product identifiers linked on the page | `B098WFBBJZ` |
| `searchKeyword` | Keyword that yielded the item | `garlic press` |
| `searchPosition` | One-based position in search collection | `1` |
| `sponsored` | Whether the search card has a sponsored label | `false` |
| `detailStatus` | `full` or `listing` | `full` |
| `scrapedAt` | UTC collection time | ISO 8601 timestamp |

The `estimatedMonthlySales` name keeps sales data easy to compare with product feeds that use that field, while `salesEstimateMethod` records what it means here. If a badge says `4K+ bought in past month`, the actor sets the value to 4,000. Actual purchases may be higher. The revenue field then multiplies 4,000 by the current displayed item price. It excludes tax, shipping, returns, fees, discounts applied at checkout, and variation-level differences. If the badge or price is absent, the corresponding calculation remains empty. Rank alone does not produce a sales number.

### How to scrape Amazon products and sales signals

1. Choose one source: search keywords for discovery, product URLs for a known shortlist, or ASINs for a catalog you already have. The actor rejects an input that mixes those source modes, which keeps one run’s scope clear.
2. Select the marketplace. The default is the United States marketplace. For keyword and ASIN modes, the selection controls the domain and proxy country. Direct product URLs keep the marketplace in each URL.
3. Set `maxResultsPerKeyword` and `maxItems`. A small first run makes it easy to check the category and purchase signals before collecting a wider set. Turn `fullDetails` off if search-card fields are enough.
4. Start the run. Results appear as one dataset row per unique ASIN. Open the dataset to review the fields or download it in a structured format for further analysis.

The collection stops at your configured cap, at the end of reachable search pages, or when the dataset budget is reached. Search results are deduplicated across pages and keywords, so a repeated ASIN appears once per run. Direct product inputs are also deduplicated.

### Input

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `keywords` | string list | empty | Search phrases; choose this mode for product discovery. |
| `startUrls` | URL list | empty | Direct product links with `/dp/` or `/gp/product/`. |
| `asins` | string list | empty | Ten-character product identifiers for direct lookup. |
| `marketplace` | string | `com` | Domain suffix for searches and ASIN lookups. |
| `maxResultsPerKeyword` | integer | `50` | Unique products to collect for each keyword, up to 500. |
| `maxItems` | integer | `100` | Total dataset cap; zero removes the total cap. |
| `fullDetails` | boolean | `true` | Fetch each search result’s product page for detail fields. Direct lookups always need a product page. |
| `proxyConfiguration` | object | automatic | Optional proxy settings; normal runs start with datacenter sessions. |

Example search input:

```json
{
  "keywords": ["garlic press"],
  "marketplace": "com",
  "maxResultsPerKeyword": 30,
  "maxItems": 30,
  "fullDetails": true
}
```

For an existing catalog, replace `keywords` with an `asins` list such as `["B098WNQ44M", "B00HEZ888K"]`. For product links, use `startUrls` with entries such as `{"url":"https://www.amazon.com/dp/B098WNQ44M"}`. These modes fetch product pages. A product that cannot be loaded or does not expose a title is skipped instead of becoming a blank dataset row.

Supported marketplace values are `com`, `co.uk`, `de`, `fr`, `it`, `es`, `ca`, `com.mx`, and `in`. The domains share the same input contract, but page labels, currency, catalog availability, and optional fields can differ. The United States marketplace is the one covered by the recorded 30-item golden run. Check a small sample before planning a large collection in another locale.

### Output example

The following values came from one product in the successful full-detail run on 27 September 2026. The example keeps the fields most useful for a product comparison and omits long feature and image lists. The actual row contains the other schema fields too.

```json
{
  "asin": "B098WNQ44M",
  "url": "https://www.amazon.com/dp/B098WNQ44M",
  "marketplace": "com",
  "title": "Kitessensu High Effective Garlic Press With Studs, Heavy Duty Garlic Mincer, Easy to Squeeze and Clean, Rust Proof, Ginger Crusher- Imperial Silver",
  "brand": "KITESSENSU",
  "price": "$8.99",
  "rating": 4.6,
  "reviewCount": 16105,
  "boughtInPastMonth": "4K+",
  "estimatedMonthlySales": 4000,
  "estimatedMonthlyRevenue": "$35,960.00",
  "salesEstimateMethod": "boughtBadgeFloor",
  "bestSellersRank": [
    {"rank": 913, "category": "Kitchen & Dining"},
    {"rank": 4, "category": "Garlic Presses"}
  ],
  "availability": "In Stock",
  "searchKeyword": "garlic press",
  "searchPosition": 1,
  "detailStatus": "full"
}
```

The site’s `4K+` bucket means at least 4,000 purchases in the past month. The revenue floor in this example is 4,000 × $8.99. It is a product-level gross merchandise calculation, not seller income or profit. Price and badge are snapshots; rerunning later can produce different values.

### Use cases

- **Seller research:** Search a niche, then sort products by purchase bucket, rank, price, and review volume to find items that deserve deeper investigation. Compare several related phrases because search ordering and sponsored placements change what appears first.
- **Competitive tracking:** Supply an ASIN list on a schedule to watch current prices, availability, visible seller names, and category ranks. Retain each run’s timestamp so changes can be plotted over time.
- **Catalog audits:** Fetch known product URLs to extract descriptions, feature bullets, dimensions, materials, and related identifiers. The `specs` object keeps the labels as shown on each product page.
- **Retail assortment planning:** Compare purchase floors and ratings for candidate categories. Treat a missing purchase badge as missing information; it does not mean zero demand.
- **Market reporting:** Use the lower-bound revenue calculation to form a conservative visible-signal segment report. Aggregate with care because product variants, duplicated listings, and changing prices can affect totals.
- **Price monitoring:** Collect a consistent keyword set repeatedly and compare the displayed current price with a displayed list price when both exist. The actor computes `discountPercent` only from those two visible prices.

### How much does it cost to scrape Amazon products?

The configured dataset-item price is **$4.44 per 1,000 delivered products**, or $0.00444 per item. At that rate, 100 delivered products cost about **$0.44**, 1,000 cost **$4.44**, and 5,000 cost **$22.20**. A 30-product check corresponds to about **$0.13** of dataset-item charges. Charges follow successfully delivered rows; an unavailable direct product that creates no row does not add a dataset item.

The price examples describe the actor’s per-result charge. Large full-detail jobs make more page requests than listing-only jobs and may use extra proxy resources if the target starts refusing pages. Platform account terms and any separately metered resources should be checked in your run details. The actor stops pushing items if the platform reports that the run’s charge limit has been reached. Set `maxItems` to bound output count before running a broad set of keywords.

### Tips for best results

Use a specific phrase when you need a coherent product set. A broad query such as `kitchen tools` can mix unrelated items, while `stainless garlic press` gives a more focused comparison. Search placement is a discovery signal, not a permanent rank: the same product can move when time, location, availability, or sponsored inventory changes. Record the keyword and collection time together with the price and purchase badge.

Use `fullDetails: true` for best-seller rank, specifications, review distribution, seller, product images, and variant identifiers. Listing-only mode makes fewer requests and is better for quick scans of title, price, rating, review count, image, and the visible purchase bucket. If a product page is refused during keyword mode, the actor can still retain the listing row and mark `detailStatus` as `listing`. This preserves an otherwise useful search result while clearly showing which detail fields were unavailable.

When comparing marketplaces, keep currency in view. `estimatedMonthlyRevenue` uses the currency and amount displayed for that item, and values from different currencies should not be added without conversion. Product selection also varies by marketplace. Run each market with its matching suffix, and use a small sample to confirm that the needed labels are present in that locale.

For more than one keyword, `maxResultsPerKeyword` applies separately while `maxItems` applies to the whole run. The actor avoids duplicate ASINs across keyword pages. A product found under two phrases keeps the first `searchKeyword` and `searchPosition` that yielded it. If keyword attribution for every phrase matters, use separate runs per phrase and join the exports afterward.

### Limits

Amazon can return a refusal page, a challenge, an error page with a successful status code, or a different product layout. The actor checks for actual search-card or title markers, rotates the datacenter session, and can escalate proxy type after repeated failures. A refused search page can end pagination early. A refused product page in keyword mode leaves a listing-only row; a refused direct lookup is skipped. No collection process can guarantee that every visible item or every optional field will be available on every run.

Purchase badges are buckets. `4K+` gives a minimum of 4,000, not an exact count, and the true value could be materially higher. Some products show no badge at all. The actor does not fill those gaps with an unsupported best-seller-rank formula. Best-seller rank is returned separately when present; it varies by category and should not be interpreted as a direct sales count.

Review counts on search cards can be abbreviated, so listing-only values may be rounded from a `K` suffix. Full product pages can expose an exact displayed count. Review text is outside this product dataset; `reviewDistribution` contains percentages when the product page exposes them. Variants are limited to identifiers and visible option labels in the page. Variant-specific price, stock, and seller require fetching each variant as its own ASIN.

Search pages can reorder results or stop exposing further pages. The actor visits at most 20 pages per keyword and caps each keyword at 500 unique products. A large category can therefore require narrower keywords to cover distinct slices. Some product pages omit rank, description, coupon, stock count, shipping party, or seller details. Empty values represent unavailable source data, not guessed values.

### Automated workflows

The input and output schemas make recurring product collection straightforward. A workflow can submit a keyword list each morning, download the dataset, and compare purchase buckets or prices with the prior run. A second workflow can submit a fixed ASIN list and flag changes in availability or seller. Always keep the `scrapedAt` value with exported records so the observations remain tied to their collection time.

Example request: “Collect 30 garlic presses in the United States marketplace with product details, then show the products with a visible monthly purchase floor and their category ranks.” Another useful request is: “Check this ASIN list for price and availability changes and return only records whose displayed values changed since yesterday.” The actor supplies observations; any alert threshold or downstream decision belongs to the consuming workflow.

### FAQ

**Is scraping these products allowed?** This actor reads publicly visible product information. Review the site’s terms and applicable law for your use, respect rate limits and privacy rules, and avoid using collected data for personal-data misuse. The dataset is designed around products, not private customer records.

**Do I need to configure a proxy?** Usually no. The default starts with a datacenter proxy in the selected marketplace country, rotates the session when a page fails, and can escalate after repeated blocks. A custom proxy can be supplied through `proxyConfiguration` when needed.

**How fast is a run?** It depends on the input and the number of product pages. Listing-only keyword mode needs far fewer requests. Full-detail mode requests a product page per result, and retries or challenges can make a run longer. The recorded full-detail check collected 30 products; use a small run to measure your current marketplace conditions.

**Can I schedule or monitor repeated collection?** Yes. Save the same input for recurring runs and compare dataset rows using `asin`, `marketplace`, and `scrapedAt`. Watch the run status and output count; a sudden drop can indicate a source layout change or increased refusals.

**Can I export the results to a spreadsheet?** Yes. Download the dataset in a spreadsheet-friendly format or use the dataset endpoint in your own processing pipeline. Nested fields such as ranks, specs, and variants are easiest to preserve in JSON; flatten them after export if your spreadsheet needs one value per column.

**Why is a field empty?** The site may not display it for that product, the field may be available only on a detail page, or the detail page may have been refused. Check `detailStatus` first. A listing row normally has empty specifications and rank. A full row can still have empty coupon, description, stock quantity, or sales fields when the site does not show them.

**Is the monthly revenue figure actual seller revenue?** No. It is a conservative multiplication of the minimum purchase bucket and the displayed item price. It does not account for fees, returns, taxes, shipping, variation mix, or whether every purchase used the displayed price. Use it as a visible activity floor.

### Integrations

The default dataset can be consumed through an endpoint, exported to a file, or passed to scheduled workflows. Use callbacks to react when a run finishes, then combine the results with your own product catalog, reporting database, alerting process, or spreadsheet. The stable ASIN, marketplace, source keyword, and timestamp fields support repeat collection and comparisons.

### Support

Open an issue on the Issues tab; we reply within 24h and add fields on request.

# Actor input Schema

## `keywords` (type: `array`):

Search product listings for each phrase. Choose this or one direct-product input, not both.

## `startUrls` (type: `array`):

Direct Amazon product URLs using /dp/ or /gp/product/. Use instead of keywords and ASINs.

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

Ten-character product identifiers to fetch from the selected marketplace. Use instead of keywords and URLs.

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

Amazon marketplace for keyword searches and ASIN lookups. Product URLs use their own host.

## `maxResultsPerKeyword` (type: `integer`):

Maximum unique products from each keyword; search pages are visited until this cap or a site limit is reached.

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

Hard cap across all input phrases or products. Zero means no total cap.

## `fullDetails` (type: `boolean`):

Fetch each product page for rank, specifications, seller, and images. Turn off for faster keyword listing collection. Direct ASIN and URL modes always fetch product pages.

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

Uses marketplace-matched proxy country and rotates a datacenter session before residential escalation.

## Actor input object example

```json
{
  "keywords": [
    "garlic press"
  ],
  "marketplace": "com",
  "maxResultsPerKeyword": 50,
  "maxItems": 100,
  "fullDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `products` (type: `string`):

Scraped products 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 = {
    "keywords": [
        "garlic press"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mlg14/amazon-sales-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 = { "keywords": ["garlic press"] }

# Run the Actor and wait for it to finish
run = client.actor("mlg14/amazon-sales-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 '{
  "keywords": [
    "garlic press"
  ]
}' |
apify call mlg14/amazon-sales-scraper --silent --output-dataset

```

## MCP server setup

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