# Amazon Buy Box & Offers Scraper (`yasmany.casanova/amazon-buybox-scraper`) Actor

Check who wins the Amazon Buy Box for any list of ASINs in 7 countries: seller, price, shipping, FBA and Prime. Get up to 30 competing offers with seller, condition and total price, plus the lowest offer and the gap to it.

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

## Pricing

from $8.00 / 1,000 asin checkeds

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 Buy Box & Offers Scraper

Find out **who wins the Amazon Buy Box** for any list of ASINs: the seller, the price with shipping, whether Amazon fulfils the order, and **the competing offers** on the product (up to about 30), with the lowest offer and how far the Buy Box sits above it. Seven Amazon countries, up to 1000 ASINs per run.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue?logo=apify)](https://apify.com)
[![Countries](https://img.shields.io/badge/Countries-7-green)](https://www.amazon.com)

***

> ℹ️ **Zero configuration**
> Paste your ASINs or product links, pick the country and run it. No proxy, no login, no browser.

***

### Quick Start

```json
{
  "asins": ["B0FPYV6K68", "https://www.amazon.com.br/dp/B0FCYP5FB2"],
  "country": "br"
}
```

> **Tip**: Schedule the Actor to run every few hours on your catalogue to see when you lose the Buy Box and to whom.

#### More examples

<details>
<summary>US listings, from product links</summary>

```json
{
  "asins": [
    "https://www.amazon.com/dp/B09B8V1LZ3",
    "https://www.amazon.com/Harry-Potter-Chamber-Secrets-Rowling/dp/0439064872/"
  ],
  "country": "us"
}
```

</details>

<details>
<summary>Up to 30 sellers per product</summary>

```json
{
  "asins": ["B0FPYV6K68"],
  "country": "br",
  "maxOfferPages": 3
}
```

</details>

<details>
<summary>The same ASINs in Germany</summary>

```json
{
  "asins": ["0439064872"],
  "country": "de"
}
```

</details>

***

### Supported Countries

| Country | `country` | Delivery address used |
|---------|-----------|-----------------------|
| Brazil (default) | `br` | São Paulo |
| United States | `us` | New York |
| United Kingdom | `uk` | London |
| Germany | `de` | Berlin |
| France | `fr` | Paris |
| Spain | `es` | Madrid |
| Italy | `it` | Rome |

Amazon decides the Buy Box per delivery address, so each run checks it as a shopper in that city would see it. Prices come in the country's currency.

***

### Features

| Feature | Description |
|---------|-------------|
| **Buy Box Winner** | Seller name, seller ID and storefront link, condition, price, shipping and total |
| **Fulfilment** | Whether Amazon sells it, and whether Amazon ships it (FBA) or the seller does |
| **Competing Offers** | The sellers on Amazon's offer list, 10 per page, up to 3 pages (about 30 offers), with condition, price, shipping, delivery date and seller rating count |
| **Competition** | Number of offers, the lowest offer and its seller, whether the Buy Box is the lowest, and the gap to it |
| **Bulk** | Up to 1000 ASINs or product links per run, checked five at a time |
| **Fair Billing** | You pay per ASIN checked, and for extra offer pages only when you ask for them and the product has them. ASINs that are not found or fail are free |

***

### Use Cases

- **Buy Box Monitoring**: See which of your ASINs you hold and which you lost, and to whom
- **Repricing**: Feed the Buy Box price and the lowest offer into your repricing rules
- **MAP Enforcement**: Spot sellers listing below your minimum advertised price
- **Unauthorized Sellers**: List the sellers on your brand's ASINs, with their seller IDs
- **Market Research**: Check how crowded a product is before you start selling it

***

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `asins` | array | none | ASINs (e.g. `B0FPYV6K68`) or product links, one per line (**required**). Up to 1000; repeats are checked once |
| `country` | string | `br` | Amazon country to check (see the table above) |
| `maxOfferPages` | integer | `1` | Pages of Amazon's offer list to read, 10 offers each: `1` (the Buy Box and the first page, enough for most products) to `3` (about 30 offers). A page is only read when the product has more offers |

A line can hold several ASINs separated by commas, semicolons or spaces, as pasted from a spreadsheet. Product links, `/gp/product/` links and offer-listing links (`/gp/offer-listing/`) all work. An entry that is neither an ASIN nor an Amazon link is skipped, with an `error` row saying so, and the rest of the run goes on.

***

### Output Example

One row per ASIN. The competing offers are in `offers`:

```json
{
  "record_type": "buybox",
  "asin": "B0FPYV6K68",
  "country": "br",
  "served_asin": "B0FPYV6K68",
  "title": "Celular Samsung Galaxy A17, 128GB, 4GB, 50MP Tela 6.7\", IP54 - Preto",
  "brand": "Samsung",
  "url": "https://www.amazon.com.br/dp/B0FPYV6K68",
  "image_url": "https://m.media-amazon.com/images/I/61ldkLk4JYL._AC_SL1500_.jpg",
  "has_buybox": true,
  "buybox_seller": "CG CENTER GAMES",
  "buybox_seller_id": "A3RBP4KK6AUCE3",
  "buybox_seller_url": "https://www.amazon.com.br/sp?seller=A3RBP4KK6AUCE3",
  "buybox_is_amazon": false,
  "buybox_fulfilled_by_amazon": true,
  "buybox_ships_from": "Amazon",
  "buybox_condition": "Novo",
  "buybox_is_new": true,
  "buybox_price": 897.75,
  "buybox_shipping": 0.0,
  "buybox_total_price": 897.75,
  "currency": "BRL",
  "buybox_is_prime": false,
  "buybox_delivery": "Amanhã, 22 de Outubro",
  "availability": "Somente 8 em estoque.",
  "max_quantity": 8,
  "offers_count": 34,
  "offers_returned": 11,
  "offer_pages": 1,
  "lowest_offer_total_price": 854.9,
  "lowest_offer_seller": "Primetek Computadores",
  "lowest_offer_condition": "Novo",
  "buybox_is_lowest": false,
  "buybox_gap_to_lowest": 42.85,
  "offers": [
    {
      "position": 1,
      "seller": "CG CENTER GAMES",
      "seller_id": "A3RBP4KK6AUCE3",
      "seller_url": "https://www.amazon.com.br/sp?seller=A3RBP4KK6AUCE3",
      "is_buybox_winner": true,
      "is_amazon": false,
      "fulfilled_by_amazon": true,
      "ships_from": "Amazon",
      "condition": "Novo",
      "is_new": true,
      "price": 897.75,
      "shipping": 0.0,
      "total_price": 897.75,
      "delivery": "Amanhã, 22 de Outubro",
      "seller_rating_count": 163
    },
    {
      "position": 3,
      "seller": "Primetek Computadores",
      "seller_id": "A38XG6DPY3XTGC",
      "seller_url": "https://www.amazon.com.br/sp?seller=A38XG6DPY3XTGC",
      "is_buybox_winner": false,
      "is_amazon": false,
      "fulfilled_by_amazon": true,
      "ships_from": "Amazon",
      "condition": "Novo",
      "is_new": true,
      "price": 854.9,
      "shipping": 0.0,
      "total_price": 854.9,
      "delivery": "quarta-feira, 28 de Outubro",
      "seller_rating_count": 1368
    }
  ],
  "scraped_at": "2026-10-22T00:41:53.133769+00:00"
}
```

#### Two views of the same data

| View | Rows | Use it for |
|------|------|------------|
| **Buy Box** (default) | One per ASIN | Monitoring: who holds the Buy Box and at what price |
| **All offers** | One per offer | Seller lists, MAP checks, price comparisons |

Both are on the **Output** tab and export to JSON, CSV or Excel. Through the API, add `?view=offers` to the dataset items URL to get one row per offer. A `not_found` or `error` row has no offers, so in that view it appears once, with its `record_type` and `error` filled in.

***

### Data Fields

#### Per ASIN

| Field | Type | Description |
|-------|------|-------------|
| `record_type` | string | `buybox` (checked), `not_found` (no such ASIN in this country) or `error` |
| `asin` | string | The ASIN checked. For an `error` row about an invalid entry, the entry as given |
| `country` | string | Amazon country checked |
| `served_asin` | string | ASIN of the page Amazon returned. Normally the same as `asin`; see the FAQ when it is not |
| `title`, `brand` | string | Product title and brand |
| `url` | string | Product page in this country |
| `image_url` | string | Main product image |
| `has_buybox` | boolean | Whether the product has a Buy Box. See the FAQ for when it does not |
| `buybox_seller` | string | Seller holding the Buy Box. Null in the rare case Amazon shows the Buy Box price without naming the seller |
| `buybox_seller_id` | string | Amazon seller ID |
| `buybox_seller_url` | string | Seller's storefront in this country |
| `buybox_is_amazon` | boolean | Amazon itself holds the Buy Box. Null when the seller is not named |
| `buybox_fulfilled_by_amazon` | boolean | Amazon ships the order (FBA, or Amazon's own offer). Null when nothing on the page says who ships it |
| `buybox_ships_from` | string | Who ships the order |
| `buybox_condition` | string | Condition as Amazon names it in that country (`New`, `Novo`, `Used - Very Good`). Null when the page does not state it |
| `buybox_is_new` | boolean | The Buy Box offer is new. Language-neutral |
| `buybox_price` | number | Item price. Null in the rare cases the page shows no readable price, see the FAQ |
| `buybox_shipping` | number | Shipping to the country's delivery address. `0` is free shipping |
| `buybox_total_price` | number | Price plus shipping |
| `currency` | string | ISO currency code (`BRL`, `USD`, `GBP`, `EUR`) |
| `buybox_is_prime` | boolean | The Buy Box offer is Prime eligible |
| `buybox_delivery` | string | Earliest delivery date Amazon promises, as worded on the page |
| `availability` | string | Stock notice on the product page |
| `max_quantity` | number | Most units one order can take, when Amazon states it |
| `offers_count` | number | Total offers Amazon reports for the product, Buy Box included |
| `offers_returned` | number | Offers in `offers` |
| `offer_pages` | number | Pages of Amazon's offer list read for this ASIN (see `maxOfferPages`) |
| `lowest_offer_total_price` | number | Lowest price plus shipping among offers in the Buy Box's condition: new offers for a new Buy Box, used ones for a used Buy Box. Without a Buy Box, among new offers (all offers when none is new) |
| `lowest_offer_seller`, `lowest_offer_condition` | string | Who has that offer and in what condition |
| `buybox_is_lowest` | boolean | The Buy Box is the lowest offer |
| `buybox_gap_to_lowest` | number | Buy Box total minus the lowest offer's total. `0` when the Buy Box is the lowest |
| `offers` | array | The offers, as below |
| `error` | object | On `not_found` and `error` rows: `error_code`, `message` and `details` |
| `scraped_at` | string | ISO 8601 timestamp (UTC) |

#### Per offer

| Field | Type | Description |
|-------|------|-------------|
| `position` | number | Order on Amazon's offer list. The Buy Box offer comes first when Amazon leaves it off the list |
| `seller`, `seller_id`, `seller_url` | string | Seller name, ID and storefront |
| `is_buybox_winner` | boolean | This offer holds the Buy Box |
| `is_amazon` | boolean | Sold by Amazon |
| `fulfilled_by_amazon` | boolean | Shipped by Amazon (FBA) |
| `ships_from` | string | Who ships the order |
| `condition`, `is_new` | string, boolean | Condition, as worded and as a flag |
| `price`, `shipping`, `total_price` | number | Item price, shipping and their sum |
| `delivery` | string | Earliest delivery date for this offer |
| `seller_rating_count` | number | Ratings the seller has received |

***

### Integrations

Use the **API** tab on the Actor page to get ready-to-use code examples in **Python**, **JavaScript**, and **cURL**, generated with the correct parameters for immediate integration.

***

### FAQ

<details>
<summary><strong>Why is <code>has_buybox</code> false when the product has offers?</strong></summary>

Amazon sometimes gives the Buy Box to nobody: the page shows "See All Buying Options" instead of an Add to Cart button. That happens when no offer qualifies, for example when the prices are far apart or no offer ships to the delivery address. The offers are still listed in `offers`, with the lowest one in `lowest_offer_total_price`.

</details>

<details>
<summary><strong>Why is <code>offers_returned</code> lower than <code>offers_count</code>?</strong></summary>

`offers_count` is the total Amazon reports. `offers` holds the pages of Amazon's offer list the run read: the first page (about ten offers plus the Buy Box offer) by default, up to three pages with `maxOfferPages`. A book with 200 used copies still returns about 30, the first pages, where Amazon puts the most competitive offers. An offer that moves between pages while they are read is kept once.

</details>

<details>
<summary><strong>Why does the lowest offer ignore cheaper used copies?</strong></summary>

A used copy does not compete with a new Buy Box offer, so for a new Buy Box the lowest offer is taken among the new offers, and for a used Buy Box among the used ones. Each offer's `condition` and `is_new` show which is which, and the **All offers** view lists them all.

</details>

<details>
<summary><strong>Why is the Buy Box seller known but its price empty?</strong></summary>

Amazon sometimes splits the Buy Box into options, such as a one-time purchase from one seller and faster delivery from another. The page then names the seller holding the Buy Box without a readable price, and when that seller is not on the first page of offers, `buybox_price` stays empty rather than guessed. The run reports what Amazon showed at that moment; the next run usually finds the regular Buy Box again.

</details>

<details>
<summary><strong>Why is <code>served_asin</code> different from my ASIN?</strong></summary>

Amazon sometimes answers an ASIN with the page of another variation of the same product, for example after merging listings. The Buy Box data then belongs to that variation, which `served_asin` names. Check it before acting on the price.

</details>

<details>
<summary><strong>Why was my ASIN not found?</strong></summary>

ASINs are country-specific: a product sold on amazon.com is often missing from amazon.com.br. Check that the `country` matches the Amazon site the ASIN comes from. Books are the exception, since the ISBN-10 is the ASIN in every country.

</details>

<details>
<summary><strong>Does the Buy Box match what I see in my browser?</strong></summary>

Amazon decides the Buy Box per delivery address and can change it within minutes. The run checks it for an address in the country's main city (see the table above), as a shopper who is not logged in. A logged-in Prime member elsewhere in the country may see a different winner.

</details>

<details>
<summary><strong>How long does a run take?</strong></summary>

About 10 to 15 seconds per ASIN, five ASINs at a time: 100 ASINs take around five minutes. Each extra offer page adds a few seconds, and only on products that have one. Rows are saved as each ASIN finishes, so you can read the first results while the run continues.

</details>

<details>
<summary><strong>What am I charged for?</strong></summary>

One event per ASIN that returns a `buybox` row. With `maxOfferPages` above 1, one more event per extra page that brought new offers: a product whose offers fit on the first page costs the same as with `maxOfferPages` at 1. Rows of type `not_found` and `error` are not charged. A repeated ASIN in the input is checked, and charged, once.

</details>

***

### Support

1. **Check the FAQ** above for common questions
2. **Test with the prefilled example** to confirm expected output
3. **Contact support** through [Apify](https://apify.com) for additional assistance

# Actor input Schema

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

One per line: the 10-character ASIN (e.g. B0FPYV6K68) or the product link (e.g. https://www.amazon.com.br/dp/B0FPYV6K68). Up to 1000 per run; repeated ASINs are checked once.

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

Amazon country to check. The Buy Box depends on the delivery address, so the domain, language, currency and a delivery address in that country are set automatically.

## `maxOfferPages` (type: `integer`):

Amazon lists the offers 10 per page. 1 reads the Buy Box and the first page, enough for most products. 2 or 3 also read the next pages, up to about 30 offers, for products with many sellers. Extra pages are charged only when the product has them.

## Actor input object example

```json
{
  "asins": [
    "B0FPYV6K68",
    "https://www.amazon.com.br/dp/B0FCYP5FB2"
  ],
  "country": "br",
  "maxOfferPages": 1
}
```

# Actor output Schema

## `buybox` (type: `string`):

One row per ASIN: the Buy Box winner, its price and how the competing offers compare

## `offers` (type: `string`):

One row per offer, with the Buy Box winner flagged

# 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 = {
    "asins": [
        "B0FPYV6K68",
        "https://www.amazon.com.br/dp/B0FCYP5FB2"
    ],
    "country": "br",
    "maxOfferPages": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("yasmany.casanova/amazon-buybox-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 = {
    "asins": [
        "B0FPYV6K68",
        "https://www.amazon.com.br/dp/B0FCYP5FB2",
    ],
    "country": "br",
    "maxOfferPages": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("yasmany.casanova/amazon-buybox-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 '{
  "asins": [
    "B0FPYV6K68",
    "https://www.amazon.com.br/dp/B0FCYP5FB2"
  ],
  "country": "br",
  "maxOfferPages": 1
}' |
apify call yasmany.casanova/amazon-buybox-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yasmany.casanova/amazon-buybox-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/cu13SjWidcF8NVG2g/builds/yErvpuojBXqZ19CV9/openapi.json
