# Amazon Listing Monitor: Title, Price, Image & Buy Box Alerts (`amazonscrapers/amazon-listing-monitor`) Actor

Watch Amazon listings for changes. Detects edits to the title, bullet
points, main image, brand, price, list price, coupon, availability and
the buy box. One row per ASIN per check, with the old and the new value.
19 marketplaces. You only pay for rows that carry a verdict.

- **URL**: https://apify.com/amazonscrapers/amazon-listing-monitor.md
- **Developed by:** [Amazon Scrapers](https://apify.com/amazonscrapers) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 listings checked for changes

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 listing monitor: title, price, image and buy box change alerts

Give it a list of ASINs. Every time it runs, it tells you what Amazon changed on
each one since the last time you looked, with the old value next to the new one.

Someone edits your title. A bullet point gets rewritten. Your main image is
swapped for a competitor's. The buy box quietly moves to another seller. All four
happen without a notification from Amazon, and all four cost money for as long as
nobody notices.

This is the only Actor in this family built to run on a schedule rather than on
demand. It keeps a snapshot of every product you watch and compares against it,
so what you get back is not another catalogue dump but a short answer per
product: changed, unchanged, or seen for the first time.

### Read this before your first run

Three things decide whether this is what you want, and all three are easier to
learn now than after a month of runs.

**The first run cannot find changes.** There is nothing to compare against yet,
so every product comes back as `first-seen` and every one is charged. That first
run is what makes the second one useful. Budget for it: watching 500 products
costs $2.03 the first day and the same every day after, because the price is per
product checked, not per change found.

**It charges for the answer, not for the news.** A product that did not change is
a result you asked for and paid to be sure of. Charging only when something
changed would sound generous and would make this Actor lose money on the quiet
days, which are most days, and an Actor that loses money gets switched off. The
honest version is the one you are reading.

**It watches eleven fields, and six of them only when Amazon shows a buy box.**
Always compared: title, bullet points, main image, brand, and the number of other
sellers. Compared only when the buy box arrived on both checks: price, list price,
coupon, price source, stock status and availability text. Every row carries
`buyBoxSeen` so you can tell which kind of check you got. Ratings and review counts are deliberately not
watched: they drift every day on their own, so watching them would mean an alert
every day about nothing.

### What it answers

Every row carries one of three verdicts in `changeStatus`.

| Verdict | What it means |
| --- | --- |
| `first-seen` | No snapshot existed. One has been saved. Nothing to compare yet. |
| `unchanged` | Every watched field is identical to last time. |
| `changed` | At least one watched field moved. `changedFields` names them, `changes` holds the old and new value. |

A row with no verdict at all is a product whose page did not arrive complete.
That row is delivered anyway, with whatever did arrive, and it is never charged
for. This matters more than it sounds: a half-loaded page is missing bullet
points, and comparing that against yesterday would report a bullet rewrite that
never happened. A false alarm is the one failure this Actor cannot afford, so it
refuses to guess.

### Every field it returns

#### Price and offer

| Field | What it holds |
| --- | --- |
| `price` | Current price from Amazon's own buy box data |
| `listPrice` | The struck-through price, when Amazon shows one |
| `currency` | Three-letter code, from the page itself |
| `priceSource` | Where the price came from, so you can audit it |
| `coupon` | The clip-coupon text, when there is one |
| `otherSellersCount` | How many other sellers offer it |

#### Stock and delivery

| Field | What it holds |
| --- | --- |
| `inStock` | True, false, or null when Amazon does not say |
| `availability` | Amazon's own availability sentence |

#### Identity and catalogue

| Field | What it holds |
| --- | --- |
| `asin` | The product id |
| `title` | Full product title, shortened only past 1000 characters |
| `brand` | Brand name |
| `marketplace` | Which shop this row came from |
| `url` | The page this was read from |
| `scrapedAt` | Timestamp of the read |

#### Description, media and variants

| Field | What it holds |
| --- | --- |
| `features` | The bullet points at the top |
| `image` | Main image at the largest size Amazon offers |

#### What changed

| Field | What it holds |
| --- | --- |
| `changeStatus` | changed, unchanged or first-seen, the verdict for this check **(this is what you are charged for)** |
| `changedFields` | The names of the fields that moved since last time |
| `changes` | The old and the new value for each of those fields |
| `checkedAt` | When this check ran |
| `previousCheckedAt` | When the snapshot it compared against was taken |
| `buyBoxSeen` | Whether Amazon served the buy box on this check, which decides whether price and stock could be compared at all |

### The shape of a change

`changedFields` is a plain list you can filter on. `changes` holds the detail:

```
"changeStatus": "changed",
"changedFields": ["title", "price"],
"changes": {
  "title": { "from": "Echo Dot (4th Gen)", "to": "Echo Dot (4th Gen, 2024)" },
  "price": { "from": 49.99, "to": 39.99 }
},
"checkedAt": "2026-08-30T06:12:44.108Z",
"previousCheckedAt": "2026-08-29T06:11:57.402Z"
```

Filtering for `changeStatus = changed` gives you your alert list. Filtering
`changedFields` for `priceSource` gives you the buy box events on their own,
which is usually the list people actually want first.

### What each verdict is worth watching for

**Title and bullet points.** On Amazon anyone with the right permissions can edit
a listing, and brand owners routinely find their copy rewritten by a reseller or
by Amazon's own catalogue automation. The change is silent and permanent until
someone contests it.

**Main image.** Swapped images are a common way for a competing seller to make a
listing represent their variant instead of yours.

**Price and list price.** Not as a price tracker, but as a change alert: a
`from` and a `to` on the same row is what you forward to somebody.

**Coupon.** A coupon appearing or disappearing on your own listing when you did
not put it there is worth knowing the same day.

**Price source.** This is the buy box, and it comes with an honest limit that is
worth reading twice. Price, list price, coupon, stock and the buy box itself only
exist on the page when Amazon serves the buy box, and Amazon does not always
serve it. Measured here on 30 August 2026: on one run, thirteen of twenty
products arrived without a buy box at once. Nothing had changed on Amazon.

So these six fields are only compared when the buy box was there both times. When
it was not, they are left out of the verdict entirely and `buyBoxSeen` is false on
that row, so you can see why.

The cost of that rule is stated plainly: a buy box that genuinely moves to another
seller will not be reported as a change, because from outside there is no way to
tell that apart from Amazon not serving us the buy box. What stays reliable is
title, bullet points, image, brand and seller count, and those do not live in the
buy box.

**Other seller count.** Going from one seller to four overnight means somebody
has started listing against you. This one is read outside the buy box, so it
works on every check.

### What to put in

Products, the same three ways as everywhere in this family:

- an ASIN on its own, `B09B8V1LZ3`
- a product link, `https://www.amazon.com/dp/B09B8V1LZ3`
- pasted text with an ASIN in it, `ASIN: B09B8V1LZ3`, which is what you get when
  you copy out of a spreadsheet

You can also give search terms or category links in `search`, and it will monitor
whatever comes back. Each product gets its own snapshot, so a list that shifts
between runs still works. For a fixed watch list, `productUrls` is the one you
want.

### Settings worth knowing about

| Setting | What it does |
| --- | --- |
| `productUrls` | The products to watch. ASINs, links, or pasted text. |
| `search` | Search terms or category links, if you would rather watch whatever ranks. |
| `marketplace` | Which Amazon. Nineteen available. Snapshots are kept per marketplace, so the same ASIN on `.com` and `.de` never mix. |
| `stateStoreName` | Where yesterday's snapshots live. Leave it alone unless you run two separate watch lists. |
| `maxItems` | Hard ceiling on products for this run. |
| `maxItemsPerList` | How many products to take from each search term or category. |
| `maxListPages` | How deep to page through a search or category. |
| `proxyConfiguration` | Which proxy to use. Datacenter by default. |
| `proxyCountry` | Which country to exit from. Empty means follow the marketplace. |
| `residentialFallback` | Switch the later attempts to residential addresses. Off by default; it costs more and, measured on this engine, it did not deliver more. |
| `maxAttempts` | How many times to retry a product Amazon refuses. |
| `lanes` | How many products to work on at once. |
| `minDelayMs` `maxDelayMs` `retryPauseMs` | The pacing. The defaults are deliberately unhurried. |

#### The snapshot store, in plain terms

`stateStoreName` is the name of a filing cabinet in your own Apify account. Each
product gets one folder in it, holding what the listing looked like the last time
this Actor saw it. Nothing else reads that cabinet and nothing else writes to it.

Two things follow from that. Changing the name starts a fresh cabinet, so the
next run reports everything as `first-seen` again and charges for it. And two
different watch lists that should not share a baseline need two different names.

The default, `amazon-listing-watch`, is right for almost everybody.

### How it works, in plain terms

For each product it fetches the product page, reads the eleven watched fields,
and looks in the cabinet for what it saw last time. If there is nothing there, it
files today's copy and reports `first-seen`. If there is, it compares field by
field, reports what moved, and replaces the copy with today's.

Two details make the comparison trustworthy rather than merely automatic.

Empty, blank and missing are treated as the same thing. A coupon that is absent
comes back sometimes as nothing, sometimes as an empty text, and sometimes not at
all, depending on how Amazon built the page that second. All three mean there is
no coupon, so none of them counts as a change. Without that rule this Actor would
alert on its own reading noise.

And the page has to be complete before any verdict is given. A page that arrived
with a title but no bullet points is not evidence that the bullet points were
deleted.

If Amazon refuses a page, the product is retried from a different exit address,
up to `maxAttempts` times, and once more in a second pass at the end of the run.
Only after all of that does it come back without a verdict, and free.

### What you can build with it

**A daily hijack alarm.** Run it every morning on your own catalogue, filter for
`changedFields` containing `priceSource` or `otherSellersCount`, and route those
to email or Slack. That is the whole product several companies sell as a
subscription.

**A listing integrity log.** Keep every run's dataset. Over a few months you have
a dated record of every edit anyone made to your listings, which is exactly what
Amazon asks for when you contest a change.

**Competitor watch.** Point it at twenty competitor ASINs instead of your own.
Their price moves, coupon launches and stock changes arrive on the same schedule
as your own.

**Supplier and reseller compliance.** If you set minimum advertised prices, a
daily `price` change list against your distributor's ASINs is the enforcement
report.

**Catalogue drift detection.** Amazon's own automation rewrites listings too.
Running this across a large catalogue surfaces the ones that quietly stopped
matching what you uploaded.

### Working it into your stack

Set a schedule in Apify and let it run at a fixed hour. Add a webhook on run
completion so your own system gets the dataset the moment it exists, or pull it
from the API:

```
https://api.apify.com/v2/datasets/<datasetId>/items?clean=true&format=csv
```

Filtering for the alert list is one parameter away, since `changeStatus` is a
plain string in every row.

For a first look, run it twice by hand on the same ten products a few minutes
apart. The first run will say `first-seen` ten times, the second `unchanged` ten
times, and that pair tells you more about what you are buying than any
description can.

### Marketplaces

Nineteen, from amazon.com to amazon.co.jp, and pages are read in the shop's own
language. Snapshots are stored per marketplace, so the same product watched on
two Amazons keeps two separate histories and never reports a change that is
really just a different shop.

One caveat carries over from the rest of this family: on some marketplaces Amazon
does not show a buy box to visitors it cannot place, and where there is no buy box
there is no price and no availability. On those marketplaces the price and stock
fields stay empty, and because empty and empty are equal, they simply never
report a change. Title, bullet points, image and brand still work everywhere.

### Pricing

Four dollars per thousand products checked, plus three cents to start a run. That
is four tenths of a cent per product per check.

Watching 100 products daily costs 43 cents a day, or about $13 a month. Watching
500 costs $2.03 a day. You are not charged for a product whose page did not
arrive complete, or for one that never arrived at all. Platform usage is included,
so there is no separate compute bill and no proxy bill.

The comparison is charged the same whether it found a change or not, for the
reason at the top of this page.

### The rest of this family

This Actor is one of twelve on the same engine. If your question is not "what
changed", one of these fits better:

- **Amazon Price Tracker** when you want the price itself on a schedule rather
  than an alert when it moves.
- **Amazon Stock Checker** for availability and delivery promises.
- **Amazon Offer Checker** when the question is who else is on the listing and on
  what terms.
- **Amazon Product Scraper** when you want all sixty-four fields per product.
- **Amazon Bestsellers Scraper** and **Amazon Search Results Scraper** to build
  the watch list in the first place.

They share the retry engine, the pricing model and the rule about never guessing,
so what you learn on one carries to the others.

### Questions people ask

**How often should I run it.** Once a day covers most listing edits and buy box
events. Several times a day is reasonable for a small, high value list and still
cheap.

**Why did everything come back as first-seen.** Either it was the first run, or
`stateStoreName` changed. A new store name means a new baseline.

**Can I get alerted only when something changed.** Yes, but do that on your side:
filter the dataset for `changeStatus = changed`. The Actor delivers all three
verdicts because "nothing changed" is also an answer worth having, and because a
run that only returns news gives you no way to tell news from a broken run.

**Does it tell me who changed it.** No. Amazon does not publish that, and seller
names are personal data this project does not collect. What you get is what
changed and when.

**Why is `changes` empty on a `first-seen` row.** Because there is nothing to
compare against yet. The snapshot has been saved; tomorrow's run has something to
work with.

**What happens if a run is interrupted.** Products already checked have their
snapshots saved. The rest are simply not updated, and the next run picks them up
against their older baseline.

### What it does not collect

No review text, no reviewer names, no customer questions and answers, no seller
names. Review text and reviewer names are personal data, and scraping personal
data is almost always a problem under European privacy law regardless of what you
intend to do with it. Aggregate numbers, the star rating and the review count,
are available in the sister Actors that report them.

You can see how many sellers are on a listing and watch that number move. You
cannot see who they are.

### Legal note

This Actor reads pages that Amazon serves publicly, at a deliberately unhurried
pace. It is not affiliated with, endorsed by, or connected to Amazon.com, Inc.
What you may do with the data it returns depends on where you are and what you
use it for, and that is your call to make.

# Actor input Schema

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

Amazon product URLs or bare ASINs, one per line. Leave empty if you are using Search instead. Duplicates are removed so you are never charged twice.

## `search` (type: `array`):

Anything that lists products: a plain search term ("tower fan"), an Amazon search URL, a category link, or a bestsellers page. Each one is crawled and every product found is scraped. Use this when you do not know the ASINs up front.

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

Which Amazon site to read. The currency of the price follows the marketplace and the proxy country.

## `stateStoreName` (type: `string`):

Where the monitor keeps yesterday's snapshot of each listing, so it has something to compare against. Leave it as it is unless you run two separate watch lists; a different name starts a fresh baseline and the next run reports every product as first-seen.

## `proxyCountry` (type: `string`):

Which country the requests should appear to come from. Leave empty and it follows the marketplace: amazon.de is read from Germany, amazon.co.uk from the UK. This matters more than it looks -- Amazon shows different prices, currencies and even availability depending on where you appear to be.

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

Hard ceiling on delivered products. 0 means no ceiling: the Actor keeps going until the lists run out or your limits stop it.

## `maxItemsPerList` (type: `integer`):

Products to take from each search term or category link. Up to 10000.

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

Datacenter proxies were enough in testing: 30 out of 30 products returned with zero blocks. They are the cheaper option and the default. Switch to residential if you start seeing blocked pages at higher volume. Running without any proxy stops after roughly 85-120 products, because Amazon closes the door on a single IP address for over an hour.

## `lanes` (type: `integer`):

How many products to read at the same time. Each lane uses its own exit address, so more lanes never means asking one address more often. Eight is the tested default and the most accurate. Sixteen finishes the same sixty products in about half the time, but measured on 2026-08-24 it returned six more products without a price, because Amazon strips the buy box sooner under pressure. Raise it when speed matters more than the last few prices.

## `maxAttempts` (type: `integer`):

How often to retry a product Amazon refuses, each time from a different exit IP. A refusal is a property of one address, not of the product, and a refused attempt costs about 4 KB. Twelve tries is cheap insurance against a run that comes back short.

## `residentialFallback` (type: `boolean`):

After half the attempts have failed, retry through residential addresses instead of datacenter ones. Measured 2026-08-26: residential transfer was 90 percent of the bill on a sixty product run ($0.150 of $0.167) while a run that never touched it delivered all sixty anyway. Leave it off unless you are losing products; turn it on when a marketplace refuses everything.

## `maxListPages` (type: `integer`):

Result pages to walk per list. Up to 100. Amazon itself stops earlier on most searches.

## `minDelayMs` (type: `integer`):

Pause between products. Measured 2026-08-23: at 1-2 seconds this returned 10 of 15 products; at 8-15 seconds it returned 12 of 15 on the same list. Pace turned out to matter more than anything else. The market leader waits about 14 seconds per product.

## `maxDelayMs` (type: `integer`):

Upper bound for the pause between products. The actual pause is random between the minimum and this value, which looks less mechanical than a fixed interval.

## `retryPauseMs` (type: `integer`):

How long to wait before trying a refused product again. Kept short because the retry already switches to a different exit IP, and waiting longer only makes the run more expensive.

## Actor input object example

```json
{
  "productUrls": [
    "B09B8V1LZ3",
    "https://www.amazon.com/dp/B0DXXYS4BJ"
  ],
  "search": [],
  "marketplace": "com",
  "stateStoreName": "amazon-listing-watch",
  "maxItems": 0,
  "maxItemsPerList": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "lanes": 8,
  "maxAttempts": 12,
  "residentialFallback": false,
  "maxListPages": 5,
  "minDelayMs": 8000,
  "maxDelayMs": 15000,
  "retryPauseMs": 300
}
```

# Actor output Schema

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

One row per product per check: changed, unchanged or first-seen, with the old and new value for every field that moved. Products whose page did not arrive complete are delivered and never charged for.

## `summary` (type: `string`):

Counts per outcome, exit addresses used, bytes per charged result.

# 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": [
        "B09B8V1LZ3",
        "https://www.amazon.com/dp/B0DXXYS4BJ"
    ],
    "search": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("amazonscrapers/amazon-listing-monitor").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": [
        "B09B8V1LZ3",
        "https://www.amazon.com/dp/B0DXXYS4BJ",
    ],
    "search": [],
}

# Run the Actor and wait for it to finish
run = client.actor("amazonscrapers/amazon-listing-monitor").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": [
    "B09B8V1LZ3",
    "https://www.amazon.com/dp/B0DXXYS4BJ"
  ],
  "search": []
}' |
apify call amazonscrapers/amazon-listing-monitor --silent --output-dataset

```

## MCP server setup

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

```

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/CY7htH9f9fyZFcK3k/builds/p9anhS4VhHZhCIdSK/openapi.json
