# Amazon Product Scraper & Change Monitor (`ficuslink/amazon-product-scraper-change-monitor`) Actor

Scrape Amazon products, search results, categories, bestsellers, sellers, and competitor sets across 19 marketplaces. Run one-time collection or deterministic change monitoring with structured outputs, uncharged error records, and optional change webhooks.

- **URL**: https://apify.com/ficuslink/amazon-product-scraper-change-monitor.md
- **Developed by:** [KIM SK](https://apify.com/ficuslink) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Product Scraper & Change Monitor

Bulk Amazon collection and deterministic change monitoring for Apify. The Actor uses HTTP collection first and retries blocked or incomplete pages with Playwright. It does not call an AI model, solve CAPTCHAs, or generate quality, fraud, or risk judgments.

This Actor is independently developed and is not affiliated with, endorsed by, or sponsored by Amazon.

### Quick start

The Store example searches Amazon.com for `laptop` and returns one detailed product. Replace the query or select another input mode for your own run.

```json
{
  "mode": "search",
  "queries": ["laptop"],
  "marketplaces": ["amazon.com"],
  "maxItems": 1,
  "maxItemsPerSource": 1,
  "maxSearchPages": 1,
  "maxConcurrency": 1
}
```

The Store form uses this as a `prefill` example only. API and Task runs still use the input you provide together with the schema defaults.

### What it collects

- Product pages from ASINs and URLs
- Search, category, and bestseller listings with rank and placement
- Seller storefronts and their products
- A reference product and up to 50 competitors with numeric differences
- Repeated snapshots and deterministic changes across all source types

Supported marketplaces:

`amazon.com`, `amazon.co.uk`, `amazon.in`, `amazon.de`, `amazon.fr`, `amazon.es`, `amazon.it`, `amazon.ca`, `amazon.co.jp`, `amazon.com.au`, `amazon.com.br`, `amazon.com.mx`, `amazon.nl`, `amazon.sg`, `amazon.sa`, `amazon.ae`, `amazon.pl`, `amazon.se`, `amazon.com.be`

### Modes

| Mode | Purpose |
| --- | --- |
| `products` | Collect multiple ASINs and product URLs. |
| `search` | Discover products from queries, search URLs, categories, or bestsellers. |
| `seller` | Collect seller profiles and products belonging to their storefronts. |
| `compset` | Compare one reference product with up to 50 competitors using price, stars, review count, and BSR differences. |
| `monitor` | Repeat any supported product, listing, or seller input and compare it with saved state. `monitorName` is required. |

Example monitor input:

```json
{
  "mode": "monitor",
  "monitorName": "coffee-grinders-us",
  "queries": ["burr coffee grinder"],
  "marketplaces": ["amazon.com"],
  "maxItems": 100,
  "scrapeProductDetails": true,
  "captureScreenshotOnChange": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

The input editor documents all limits and optional fields. Residential Apify Proxy is the default. Proxy country follows the marketplace unless `proxyCountry` is set. A user-provided `proxyConfiguration` replaces the default.

#### Junglee compatibility

The Actor accepts `categoryOrProductUrls`, `maxItemsPerStartUrl`, `maxProductVariantsAsSeparateResults`, and `scrapeProductVariantPrices`. Set `outputProfile` to `compat` to retain Junglee's public field names and money shape (`{ value, currency }`). Monitoring metadata is added under `_monitor`.

### Results

The default Dataset contains:

- `product`: a successful product inspection
- `seller`: a successful seller profile
- `error`: an uncharged failure such as CAPTCHA, blocking, not found, or parsing failure

Successful product states are `snapshot`, `unchanged`, `changed`, `new`, or `missing`. Product records include `current`, `previous`, `changes`, `fieldStatus`, source details, and the inspection time. A field marked `parse_failed` retains its last good value and is not reported as a change.

Every run creates four run-scoped Datasets with direct output links:

- `All results`: every product, seller, and uncharged error record
- `Changes`: only `changed`, `new`, and confirmed-`missing` product records
- `Errors`: only uncharged input, blocking, CAPTCHA, not-found, and parsing errors
- `Sellers`: only successful seller profiles

The non-default Datasets follow the run's retention policy rather than creating persistent named storage. A record mirrored from `All results` into `Changes` or `Sellers` is charged only once. The default Key-Value Store record `OUTPUT` contains the exact Dataset URLs together with counts, truncation, billing, and webhook delivery status.

### Monitoring rules

- The first successful inspection becomes `snapshot`.
- A product first discovered by an already-established listing becomes `new`.
- Numbers, currencies, whitespace, tracking parameters, and set-like arrays are normalized before comparison.
- Price, seller, availability, title, bullets, images, variants, BSR, and search rank can produce changes.
- A listing product becomes `missing` only after two consecutive complete runs do not contain it.
- A blocked, truncated, or partially parsed source does not update the source baseline or confirm missing products.
- A queue-backed lease prevents two runs with the same user and `monitorName` from running concurrently.
- The result is stored and the PPE event succeeds before monitor state is committed. A crash can therefore repeat an event, but cannot silently move the baseline past an undelivered result.
- Change webhooks accept HTTPS only, use a stable event ID, and retry transient failures three times.
- Optional screenshots are captured only for `changed` products and stored in the run Key-Value Store.

### Charging and platform costs

Successful visible product and seller records use the custom PPE event `result`. This includes `unchanged` product checks because they remain visible Dataset results. Errors, CAPTCHAs, invalid pages, and failed runs do not use the event.

The Actor intentionally does not use the automatic `apify-default-dataset-item` event or a paid Actor-start event. When the user's maximum charge is reached, new useful work stops and the completed results plus `OUTPUT` summary remain available.

The commercial setting is **PPE with platform usage passed through**. The custom `result` event costs **$0.003 per successful result ($3 per 1,000 results)**. Compute, residential proxy traffic, storage, and other Apify platform usage are charged separately to the Actor user, not absorbed by the developer. Platform usage already consumed can still be charged when a page is blocked or a result fails, even though the failed result itself does not trigger the creator's `result` fee.

The Actor has no paid start event. The Store form includes a bounded `laptop` search example so a new user can run one product immediately. Replace it with at least one ASIN, URL, query, seller, or comparison target for real work. A targetless input fails validation before scraping and does not trigger the creator's `result` fee.

### Development

Requirements: Node.js 22 or later, npm, and Docker for container validation.

```bash
npm install
npm run check
docker build -t amazon-product-scraper-change-monitor .
```

For a direct local run, place input in `storage/key_value_stores/default/INPUT.json` and run:

```bash
npm start
```

The default residential proxy configuration needs valid Apify credentials. For parser-only local experiments, explicitly set `proxyConfiguration` to `{ "useApifyProxy": false }`.

### Reliability boundary

Amazon can vary markup, availability, rank, price, seller, delivery, and returned offers by location and time. A successful run proves what was visible for that run; it does not guarantee that Amazon will return the same page or values later. The Actor does not bypass CAPTCHAs or certify product quality, seller trustworthiness, legal compliance, or purchasing decisions.

# Actor input Schema

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

Choose a one-time collection mode or monitor all supported source types over repeated runs.

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

Amazon ASINs. Each ASIN is checked in every selected marketplace.

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

Amazon product URLs from any supported marketplace.

## `queries` (type: `array`):

Keywords searched in every selected marketplace.

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

Amazon search result, category, bestseller, or product URLs.

## `sellerUrls` (type: `array`):

Amazon seller profile or storefront URLs.

## `product` (type: `string`):

ASIN or product URL used as the reference in compset mode.

## `competitors` (type: `array`):

Up to 50 competitor ASINs or product URLs.

## `marketplaces` (type: `array`):

Marketplaces used for ASINs and queries. URLs retain their own marketplace.

## `language` (type: `string`):

Optional Accept-Language value, for example en-US.

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

Optional ISO 3166-1 alpha-2 override. By default it follows the marketplace.

## `deliveryCountry` (type: `string`):

Optional delivery-country hint for the Amazon page.

## `zipCode` (type: `string`):

Optional delivery ZIP or postal code.

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

Maximum successful product results for the run.

## `maxItemsPerSource` (type: `integer`):

Maximum products discovered from each listing source.

## `maxSearchPages` (type: `integer`):

Maximum pages visited for each listing source.

## `scrapeProductDetails` (type: `boolean`):

Open each discovered product page for detailed fields.

## `maxOffers` (type: `integer`):

Zero disables separate offer-page collection.

## `scrapeSellers` (type: `boolean`):

Open seller profiles found on product and offer pages.

## `scrapeVariantPrices` (type: `boolean`):

Open variants whose prices are not visible on the base page.

## `includeProductPageReviews` (type: `boolean`):

Copy reviews visible on the product detail page.

## `sort` (type: `string`):

Optional Amazon sort code, such as price-asc-rank or review-rank.

## `minPrice` (type: `number`):

Optional minimum search price.

## `maxPrice` (type: `number`):

Optional maximum search price.

## `category` (type: `string`):

Optional Amazon search alias such as electronics.

## `monitorName` (type: `string`):

Stable name for saved state. Required in monitor mode.

## `outputProfile` (type: `string`):

Choose full records, Junglee-compatible fields, or compact records.

## `maxConcurrency` (type: `integer`):

Maximum parallel page requests.

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

Residential Apify Proxy is used by default. Custom proxy settings override it.

## `captureScreenshotOnChange` (type: `boolean`):

Capture a browser screenshot only for changed products.

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

HTTPS endpoint notified for changed, new, and confirmed-missing records.

## `webhookHeaders` (type: `object`):

Optional authentication headers. Values are stored as secrets.

## `categoryOrProductUrls` (type: `array`):

Compatibility alias for category and product URLs.

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

Compatibility alias for maxItemsPerSource.

## `maxProductVariantsAsSeparateResults` (type: `integer`):

Maximum variants emitted as separate product results.

## `scrapeProductVariantPrices` (type: `boolean`):

Compatibility alias for scrapeVariantPrices.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "laptop"
  ],
  "marketplaces": [
    "amazon.com"
  ],
  "maxItems": 1,
  "maxItemsPerSource": 1,
  "maxSearchPages": 1,
  "scrapeProductDetails": true,
  "maxOffers": 0,
  "scrapeSellers": false,
  "scrapeVariantPrices": false,
  "includeProductPageReviews": false,
  "outputProfile": "full",
  "maxConcurrency": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "captureScreenshotOnChange": false,
  "maxProductVariantsAsSeparateResults": 0
}
```

# Actor output Schema

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

Every successful check and every uncharged error record.

## `changes` (type: `string`):

Changed, new, and confirmed-missing records.

## `errors` (type: `string`):

Uncharged blocked, CAPTCHA, not-found, invalid, and parse-failure records.

## `sellers` (type: `string`):

Seller profiles produced by seller and offer collection.

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

Run counts, billing counts, truncation, and webhook status.

## `screenshots` (type: `string`):

Optional screenshots captured only for changed products.

# 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 = {
    "mode": "search",
    "queries": [
        "laptop"
    ],
    "marketplaces": [
        "amazon.com"
    ],
    "maxItems": 1,
    "maxItemsPerSource": 1,
    "maxSearchPages": 1,
    "maxConcurrency": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("ficuslink/amazon-product-scraper-change-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 = {
    "mode": "search",
    "queries": ["laptop"],
    "marketplaces": ["amazon.com"],
    "maxItems": 1,
    "maxItemsPerSource": 1,
    "maxSearchPages": 1,
    "maxConcurrency": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("ficuslink/amazon-product-scraper-change-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 '{
  "mode": "search",
  "queries": [
    "laptop"
  ],
  "marketplaces": [
    "amazon.com"
  ],
  "maxItems": 1,
  "maxItemsPerSource": 1,
  "maxSearchPages": 1,
  "maxConcurrency": 1
}' |
apify call ficuslink/amazon-product-scraper-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ficuslink/amazon-product-scraper-change-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/U8zkDovYYQmtN85gC/builds/BrAkJUuE8redlGwg3/openapi.json
