# Amazon ASIN Scraper By Country & Marketplace (`scraper-engine/amazon-asins-scraper`) Actor

The Amazon ASIN Scraper actor extracts ASINs, product titles, prices, ratings, and URLs from Amazon search results or category pages. It automates large-scale product data collection for market research, competitor analysis, and pricing insights. Ideal for e-commerce and data intelligence tasks.

- **URL**: https://apify.com/scraper-engine/amazon-asins-scraper.md
- **Developed by:** [Scraper Engine](https://apify.com/scraper-engine) (community)
- **Categories:** E-commerce, Automation, Lead generation
- **Stats:** 25 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$19.99/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period.You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#rental-actors

## 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 ASIN Scraper — Prices, Currency and Availability by Country

Amazon ASIN Scraper By Country & Marketplace prices a list of ASINs across many Amazon storefronts in a single run and returns one row per ASIN **and** marketplace: `priceValue` with `currencyCode` in that storefront's own currency, an added `priceUsd` for ranking, plus `priceRank`, `cheapestMarketplace`, `priceGapPercent`, `isAvailable` and `availabilityStatus`. Everything comes back as typed JSON with a stable schema — no HTML parsing, no selectors. Add your ASINs, pick the storefronts, start the run.

### What is Amazon ASIN Scraper By Country & Marketplace?

It is an Apify Actor that takes one ASIN list and prices it on every Amazon country storefront you name. Each storefront is fetched with **its own locale cookie and Accept-Language**, so `amazon.de` answers in euros and `amazon.co.uk` in pounds instead of an Amazon-converted USD figure — and every row records which cookie was sent, in `localeCookieSent`, so the currency is auditable rather than assumed.

No Amazon account, login, cookie or Product Advertising API key is required. Every field returned is what an anonymous shopper on that country's product page already sees.

It is built for pricing and arbitrage analysts, marketplace expansion teams, procurement and reselling operations, and developers piping cross-border product data into an internal tool or an agent.

### What Amazon product data is publicly available to scrape?

Amazon renders the full commercial offer on a `/dp/` product page before any login: title, buy-box price in the storefront's currency, availability, rating, review count, bestseller rank and A+ marketing content. What is gated is account-level and seller-level data, not product data.

| Data Category | Publicly Available | Behind an Amazon account / Seller Central |
| ----- | ----- | ----- |
| Title, brand, images, feature bullets, specs | ✅ Public | — |
| Buy-box price, list price, currency, shipping message | ✅ Public | — |
| Availability and stock wording | ✅ Public | — |
| Star rating, review count, rating histogram percentages | ✅ Public | — |
| Bestseller ranks, Amazon's Choice badge, monthly purchase wording | ✅ Public | — |
| A+ content, brand story, product comparison table, AI review summary | ✅ Public | — |
| Individual review text and reviewer identity | ❌ | Amazon serves logged-out shells on review surfaces |
| Buyer identity, order and payment history | ❌ | Account |
| Seller inventory, fees, internal sales figures | ❌ | Seller Central |
| Historical price series, and Amazon's own cross-marketplace FX rate | ❌ | Amazon publishes neither |

Amazon ASIN Scraper By Country & Marketplace only returns publicly visible data — what any visitor to that country's product page sees. Nothing behind a login wall.

### What data can I extract with Amazon ASIN Scraper By Country & Marketplace?

A successfully parsed row carries 85 keys, spanning cross-marketplace pricing and ranking, the product record itself, ratings and demand signals, rich marketing content, and per-request run accounting.

| Field Name | Description |
| ----- | ----- |
| `asin` | The ASIN, uppercased and normalized from your input |
| `originalAsin` | Same value, kept for parity with single-marketplace Amazon Actors |
| `marketplace` | Storefront domain this row was priced on, e.g. `amazon.de` |
| `marketplaceCountry` | ISO-3166 alpha-2 country of the storefront; `null` for a domain outside the built-in map |
| `marketplaceCurrency` | ISO-4217 currency the storefront natively quotes in, from the built-in map |
| `priceValue` | Buy-box price as a number, in the storefront's own currency |
| `priceCurrency` | Display symbol detected on the page (`€`, `£`, `S$`, `zł`, …) |
| `currencyCode` | ISO-4217 code detected on the page; `null` when the page showed no currency token |
| `priceIsNativeCurrency` | `true` when `currencyCode` matches `marketplaceCurrency` — the flag that catches an Amazon-converted price |
| `price` | Nested `{ "value", "currency" }` object for the same buy-box price |
| `listPrice` | Nested `{ "value", "currency" }` strike-through price, `null` when equal to `price` |
| `priceRange` | Price range string when Amazon shows a range instead of one price |
| `priceUsd` | `priceValue` converted to USD for ranking; `null` when no rate was available |
| `fxRateToUsd` | The rate used for this row's currency, as returned by the reference feed |
| `fxRatesDate` | Date the feed itself reports for that rate set |
| `priceComparisonBasis` | How this ASIN's storefronts were ranked: `usd_ecb_reference`, `usd_ecb_reference_partial`, `same_currency` or `none` |
| `priceRank` | 1-based cheapest-first rank of this storefront for this ASIN; `null` if unpriced |
| `isCheapestMarketplace` | `true` on the rank-1 row, `null` when this row was not ranked |
| `cheapestMarketplace` | Domain of the cheapest storefront for this ASIN in this run |
| `cheapestPriceUsd` | `priceUsd` of that cheapest row; `null` when the ranking ran without FX |
| `priceGapPercent` | How much more expensive this row is than the cheapest, in percent |
| `marketplacesCompared` | Number of storefronts configured for the run |
| `marketplacesPriced` | Number of those storefronts that produced a comparable price |
| `isAvailable` | `true` / `false` / `null` — `null` means undetermined, not unavailable |
| `availabilityStatus` | Reason behind `isAvailable`; one of nine values listed below |
| `inStock` | Raw stock boolean parsed from Amazon's availability block |
| `inStockText` | Amazon's own availability wording, in the storefront's language |
| `title` | Product title as rendered on that storefront |
| `brand` | Brand or byline name |
| `author` | Author, for book and media listings |
| `description` | Product description text |
| `bookDescription` | Book/editorial description, populated only when `description` is empty |
| `features` | "About this item" bullet list |
| `attributes` | Spec and detail rows as `{ "key", "value" }` pairs |
| `productOverview` | Amazon's product-overview table as `{ "key", "value" }` pairs |
| `breadCrumbs` | Category path joined with `>` |
| `thumbnailImage` | Main product image URL |
| `galleryThumbnails` | Gallery thumbnail URLs |
| `highResolutionImages` | Full-resolution image URLs |
| `videosCount` | Number of product videos detected |
| `variantAsins` | Sibling variant ASINs found on the page |
| `variantDetails` | Variants as `{ "name", "thumbnail", "images", "asin", "price" }` |
| `variantAttributes` | Selected variant dimensions as `{ "key", "value" }` pairs |
| `stars` | Average star rating |
| `starsBreakdown` | Rating histogram keyed `5star` … `1star`, values as 0–1 fractions |
| `reviewsCount` | Number of ratings |
| `hasReviews` | `true` when `reviewsCount` is above zero |
| `reviewsLink` | Constructed link to the storefront's review page |
| `answeredQuestions` | Answered-questions count when Amazon renders one |
| `monthlyPurchaseVolume` | Amazon's "N bought in past month" wording, as displayed |
| `bestsellerRanks` | List of `{ "rank", "category", "url", "categoryNodeId" }` |
| `isAmazonChoice` | Amazon's Choice badge flag |
| `amazonChoiceText` | Badge label, normalized when Amazon renders a long blob |
| `seller` | `{ "name", "id", "url", "reviewsCount", "averageRating" }`, or `null` when nothing was found |
| `shipsFrom` | Fulfilment source from the buy box |
| `shippingPrice` | Nested `{ "value", "currency" }`; `0.0` when shipping reads as free |
| `delivery` | Primary delivery promise text |
| `fastestDelivery` | Fastest delivery promise text |
| `condition` | New / used condition label |
| `returnPolicy` | Return-policy text |
| `support` | Product-support text |
| `importantInformation` | Ingredients, safety and legal disclaimer block |
| `sustainabilityFeatures` | `{ "summary", "certifications" }` from Climate Pledge blocks |
| `aPlusContent` | `{ "title", "rawText", "rawImages", "rawVideos", "modules" }` |
| `brandStory` | `{ "title", "image", "items" }` brand-story carousel |
| `productComparison` | `{ "products": [ { "asin", "title", "thumbnail", "price", "stars", "reviewsCount" } ] }` |
| `aiReviewsSummary` | `{ "text", "keywords" }` from Amazon's review-insights widget |
| `url` | Canonical product URL on this storefront |
| `unNormalizedProductUrl` | `/dp/` URL, carrying `?language=` when a language was set |
| `input` | The `/dp/` URL this row was fetched from |
| `visitStoreLink` | Brand store link on this storefront |
| `locationText` | Amazon's delivery-location header text |
| `loadedCountryCode` | Delivery country Amazon actually applied to the page |
| `pageLanguageTag` | `<html lang>` of the served page — proof of which locale Amazon returned |
| `localeStrategy` | The currency mode this row was fetched under |
| `localeCookieSent` | The exact locale cookie string sent, or `null` when none was sent |
| `buyBoxDegraded` | `true` when Amazon served an unqualified buy box, so a missing price is a page state and not a parse failure |
| `hasCorePriceDisplay` | `true` when a core price container was present at all |
| `fetchOutcome` | `ok`, `not_listed`, `blocked`, `fetch_failed` or `parse_error` |
| `httpStatus` | HTTP status of the last attempt |
| `responseBytes` | Size of the response body — the signal used to detect a CAPTCHA shell |
| `usedProxy` | Whether the successful attempt went through a proxy |
| `proxyCountryUsed` | Exit country actually used, after any storefront override; `null` when unproxied |
| `position` | Sequence number of this parsed page within its storefront |
| `scrapedAt` | UTC run timestamp, identical on every row of the run |
| `error` | Present **only** on rows where no product record could be parsed |

#### Cross-marketplace pricing and ranking fields

These are the reason this Actor exists. `priceValue`, `priceCurrency` and `currencyCode` are read from the page as served; `marketplaceCurrency` is what that storefront is supposed to quote in; `priceIsNativeCurrency` compares the two, so a row where Amazon quietly served a converted price is visible instead of silently wrong. `priceUsd`, `priceRank`, `cheapestMarketplace`, `cheapestPriceUsd` and `priceGapPercent` are computed **per ASIN across the storefronts of the same run**, and `priceComparisonBasis` records which method produced the ranking. `marketplacesCompared` and `marketplacesPriced` tell you how many storefronts were asked versus how many answered with a usable price.

#### Availability fields

`isAvailable` is deliberately three-valued. `availabilityStatus` says why: `in_stock`, `out_of_stock`, `listed_price_shown`, `not_listed_in_marketplace`, `listed_no_buy_box`, `unknown_degraded_buy_box`, `unknown_blocked`, `unknown_fetch_failed` or `unknown_no_data`. The three `unknown_*` values mean the Actor could not establish availability — a blocked page or a transport failure is never reported as "not sold here", because for cross-market analysis those are opposite conclusions.

#### Product, rating and rich-content fields

`title`, `brand`, `description`, `features`, `attributes` and the image arrays describe the product on that storefront and arrive in that storefront's language. `stars`, `starsBreakdown`, `reviewsCount`, `bestsellerRanks` and `monthlyPurchaseVolume` are the demand signals, and they differ per country for the same ASIN — often the most interesting part of a cross-market dataset. `aPlusContent`, `brandStory`, `productComparison` and `aiReviewsSummary` are the heavy nested blocks; they dominate record size and are largely identical across storefronts, so `includeRichContent: false` empties them for a lean price dataset.

#### 🤖 Add-on: Need additional Amazon data?

Three companion Actors cover the jobs this one deliberately does not. **Amazon Product Scraper By Bestseller & Demand Filter** starts from category or product URLs and filters on demand rather than taking a fixed ASIN list. **Amazon Today's Deals Scraper With Star Ratings & Deal Badges** works the deals surface and returns discount and badge data. **Amazon Top Rated Products Scraper** runs keyword searches with rating and review-count thresholds.

### Why not build this yourself?

Amazon's Product Advertising API exists, but it requires an approved Associates account with qualifying sales, so it is not openly available to anyone who simply wants prices — which leaves scraping. The costs are not in parsing a title.

**Locale is the hard part.** Amazon obeys the `i18n-prefs` / `lc-main` cookie you send it. Send a US cookie to `amazon.de` and Amazon answers with a converted USD figure and no euro sign anywhere on the page — a US price wearing a German URL. Getting a real German price means the right cookie, a matching `Accept-Language`, and a check afterwards that the page actually came back in the expected currency. This Actor ships a map of 20 storefronts with their country, native currency, `lc-main` value and `Accept-Language`, and reports the cookie it sent on every row.

**Currency detection is the second trap.** A naive symbol list that puts bare `$` first labels a Singapore-dollar price `S$193.73` as US dollars. The token table here is sorted longest-first so `S$`, `C$`, `MX$` and `US$` win over the `$` they contain, and `kr` — shared by SEK, NOK and DKK — is resolved from the storefront rather than guessed.

**Then there is geography.** A residential US exit pointed at a non-US Amazon domain does not fail cleanly; the Actor's source records it answering HTTP 200 with a roughly 3.8 KB CAPTCHA shell on every attempt tested. So you need per-storefront exit countries, a size-aware block detector rather than a status check, session rotation, an unproxied last attempt, backoff, and a delivery-address priming call per storefront. That is infrastructure to run and pay for before a single price is compared.

### How to use Amazon ASIN Scraper By Country & Marketplace

The Actor runs on Apify. Start it from the Apify Console or call it through the Apify API.

1. Open Amazon ASIN Scraper By Country & Marketplace on Apify and click **Try for free**
2. Paste your ASINs into **ASINs to price worldwide** — the only required input. Full `/dp/` and `/gp/product/` URLs are accepted and reduced to the ASIN automatically
3. List the domains you want in **Country storefronts to compare**, one per line, e.g. `amazon.com`, `amazon.de`, `amazon.co.uk`. Leave it empty and only `amazon.com` is scraped
4. Leave **Currency mode** on Storefront local currency and **Proxy exit country** on Match each storefront — that pairing is what returns a real local price
5. Click **Start**, then download the dataset as JSON, CSV or Excel

#### How to scale to bulk ASIN extraction

There is no per-run item cap in this Actor: the row count is exactly your ASIN count multiplied by your storefront count, before any filtering. Two ASINs on three storefronts is six rows; fifty ASINs on ten storefronts is five hundred.

Both `asins` and `marketplaces` are lists, and each entry is additionally split on whitespace, commas and semicolons — so a single pasted line holding several ASINs works. Duplicate ASINs are removed before the run, and so are duplicate domains. Pages are fetched concurrently with an internal limit of five requests in flight; that limit is set by the Actor and is not exposed as an input, so size very large jobs by splitting the ASIN list across scheduled runs rather than by tuning concurrency.

### What can you do with Amazon cross-marketplace price data?

- 💱 A **pricing analyst** hunting cross-border gaps reads `priceGapPercent` and `cheapestMarketplace` per `asin`, filters to rows where `priceIsNativeCurrency` is `true`, and gets a ranked arbitrage list without a currency spreadsheet.
- 🌍 An **expansion manager** assessing a new country pulls `isAvailable` and `availabilityStatus` for their catalogue on the target storefront and treats `not_listed_in_marketplace` rows as the whitespace list — the absences are the finding.
- 📦 A **reseller** sourcing stock compares `priceUsd` against `stars` and `reviewsCount` for the same ASIN across storefronts, using `shipsFrom` and `delivery` to weigh landed cost against lead time.
- 🏷️ A **brand protection lead** auditing distribution checks `seller` and `shipsFrom` per storefront for one ASIN, spotting the markets where the buy box is not held by the brand or by Amazon.
- 🤖 An **AI engineer** building a sourcing agent indexes `title`, `description`, `features` and `attributes` per marketplace into a vector store and keeps `priceUsd`, `currencyCode` and `isAvailable` as structured filters, so the agent can answer "where is this ASIN cheapest and actually in stock" against live data.

### How does Amazon ASIN Scraper By Country & Marketplace handle rate limits and blocking?

Requests go out over Apify Residential proxies by default, with the exit country pinned to each storefront's own country. A desktop `User-Agent` is picked per request from a five-entry pool, and a full navigation header set is sent alongside the storefront's locale cookie.

Blocking is detected by size, not by status code. Amazon answers a blocked request with HTTP 200 and a small shell, so a 200 response under 120,000 bytes that also lacks a `productTitle` element is treated as a block, as is any body carrying CAPTCHA or robot-check markers. Each ASIN-storefront cell gets four attempts: the first on a sticky session keyed to the ASIN and domain, later attempts on fresh sessions, with exponential backoff plus jitter between them. If a shell was seen, the final attempt drops the proxy entirely and tries direct. A 404 or 410 short-circuits immediately — that is not a block, it is the ASIN not being listed on that storefront, and it is recorded as such.

There is no CAPTCHA solving. A legacy `useCaptchaSolver` input is accepted for compatibility and logged as a no-op; nothing solves a challenge. A cell that cannot be recovered is still written to the dataset, with `fetchOutcome` set to `blocked` or `fetch_failed`, `isAvailable: null`, and no charge.

### ⚠️ Row counts, caps and known trade-offs

**One row per ASIN per marketplace.** Not one row per ASIN. This is the single most common misreading of the output, and it drives your row count, your cost and every `GROUP BY` you write.

**`skipUnavailableStorefronts` silently shortens your dataset.** With it on, every row whose `isAvailable` is not exactly `true` is dropped before it reaches the dataset — including `unknown_blocked` and `unknown_fetch_failed` rows. You lose the distinction between "not sold there" and "we could not tell", and your row count no longer equals ASINs × storefronts. Surviving rows still report `marketplacesCompared` for the whole run, so that field is your check on what was dropped. Default is off, which keeps the absences visible.

**`exitCountry` is resolved per storefront and overridden when it conflicts.** For any storefront in the built-in map, a requested country that is not that storefront's own is replaced with the storefront's country, logged as a warning, and reported in `proxyCountryUsed`. In practice only `MARKETPLACE_MATCH`, `NO_PROXY`, and a country that already matches the storefront are honoured. `NO_PROXY` applies to the whole run, not to one marketplace.

**`deliveryPostalCode` is one value applied to every storefront.** There is no per-marketplace postcode input. The code is primed once per storefront through Amazon's delivery-address endpoint before scraping; if a storefront rejects it, a warning is logged and that storefront is scraped without it. A US ZIP will not be meaningful on `amazon.de`.

**Legacy input keys take priority over the documented ones.** The Actor still reads the base Actor's key names, and they win: `amazonDomain` overrides `marketplaces` and forces a single-storefront run, `language` overrides `contentLanguage`, `zipCode` overrides `deliveryPostalCode`, `proxyCountry` overrides `exitCountry`, and `asinList` / `productAsins` / `storefronts` are accepted as aliases. If you call the Actor over the API, send only the documented keys.

**Silent defaults an API caller will not see in the Console.** Omit `proxyConfiguration` and the run still uses Apify Residential — that is a hardcoded fallback, not "no proxy". Omit `marketplaces` and you get `amazon.com` only. Send an unrecognised `localeStrategy` and it falls back to `native` with a warning rather than failing.

**Domains outside the built-in map still work, with less.** A domain the map does not know is fetched with no locale cookie and no pinned exit country, and returns `marketplaceCountry: null`, `marketplaceCurrency: null` and `priceIsNativeCurrency: false`.

**Field presence differs between full and error rows.** A row where no product record could be parsed carries a small key set plus an `error` key — the product fields are absent, not `null`. Code reading rows should use `.get()` rather than indexing.

**Preserved upstream quirks.** `breadCrumbs` keeps its mid-word capital, `unNormalizedProductUrl` and the generic `input` key are inherited names, `originalAsin` duplicates `asin`, `url` on a full row ends in a trailing empty `?smid=` while an error row's `url` is a plain `/dp/` link, and `seller.url` is resolved against `amazon.com` even on other storefronts. `seller.averageRating` and `seller.reviewsCount` come from an English-language pattern, so they are usually `null` on non-English storefronts.

**Malformed ASINs are dropped, not reported.** An entry that is neither a ten-character alphanumeric token nor a recognisable Amazon product URL is logged and skipped, and produces no row at all. If nothing valid survives, the run fails immediately with `Input 'asins' is required and must contain at least one valid ASIN.`

### ⬇️ Input

Ten parameters, one of them required. Everything else has a working default.

| Parameter | Required | Type | Description | Example Value |
| ----- | ----- | ----- | ----- | ----- |
| `asins` | Yes | array | ASINs to price, one per line. Full `/dp/`, `/gp/product/`, `/gp/aw/d/` and `/product/` URLs are accepted and reduced to the ASIN. Entries are also split on whitespace, commas and semicolons, uppercased and deduplicated. | `["B07GBZ4Q68", "B0CJ4V4TRP"]` |
| `marketplaces` | No | array | Storefront domains to price each ASIN on, one per line. Protocol and `www.` are stripped. Empty means `amazon.com` only. Prefilled with three domains in the Console. | `["amazon.com", "amazon.de", "amazon.co.uk"]` |
| `contentLanguage` | No | string | Page language override, sent as Amazon's `?language=` parameter. One of 21 values: `""` (storefront native) plus `en`, `en_US`, `en_GB`, `de`, `fr`, `es`, `it`, `nl`, `pl`, `pt`, `pt_BR`, `sv`, `tr`, `cs`, `da`, `ja`, `zh_CN`, `zh_TW`, `hi`, `ar`. Default `""`. | `""` |
| `localeStrategy` | No | string | Currency mode. `native` sends each storefront its own locale cookie, `forceUsd` sends a US cookie everywhere so Amazon converts, `noLocaleCookie` sends none and lets Amazon decide from the exit IP. Default `"native"`. | `"native"` |
| `convertPricesToUsd` | No | boolean | Fetch reference exchange rates once per run and fill `priceUsd`, `fxRateToUsd` and `fxRatesDate`. Default `true`. | `true` |
| `skipUnavailableStorefronts` | No | boolean | Drop every row whose `isAvailable` is not `true` before writing it. Default `false`. | `false` |
| `includeRichContent` | No | boolean | Keep `aPlusContent`, `brandStory`, `productComparison`, `aiReviewsSummary`, `highResolutionImages` and `galleryThumbnails` populated. Set `false` and the keys stay present but emptied. Default `true`. | `true` |
| `deliveryPostalCode` | No | string | One postal code, primed on every storefront through Amazon's delivery-address cookie before scraping. Empty uses each storefront's default location. Default `""`. | `"10115"` |
| `exitCountry` | No | string | Proxy exit country. One of `MARKETPLACE_MATCH`, `NO_PROXY`, `US`, `GB`, `DE`, `FR`, `ES`, `IT`, `CA`, `AU`, `JP`, `IN`, `BR`, `MX`, `NL`, `PL`, `TR`, `SE`, `AE`, `SG`. A value that conflicts with a known storefront is replaced with that storefront's own country. Default `"MARKETPLACE_MATCH"`. | `"MARKETPLACE_MATCH"` |
| `proxyConfiguration` | No | object | Apify Proxy settings. Overrides `exitCountry`; with your own `proxyUrls` the geo decision is entirely yours and no country correction is applied. Omitting it still uses Apify Residential. Prefilled `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}`. | `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` |

**Storefronts with full locale mapping.** Twenty domains have a country, native currency, `lc-main` cookie value and `Accept-Language` in the Actor's built-in map. Any other Amazon domain is still fetched, with reduced metadata.

| Domain | Country | Native currency | Domain | Country | Native currency |
| ----- | ----- | ----- | ----- | ----- | ----- |
| `amazon.com` | US | USD | `amazon.ca` | CA | CAD |
| `amazon.co.uk` | GB | GBP | `amazon.com.mx` | MX | MXN |
| `amazon.de` | DE | EUR | `amazon.com.br` | BR | BRL |
| `amazon.fr` | FR | EUR | `amazon.co.jp` | JP | JPY |
| `amazon.it` | IT | EUR | `amazon.in` | IN | INR |
| `amazon.es` | ES | EUR | `amazon.com.au` | AU | AUD |
| `amazon.nl` | NL | EUR | `amazon.sg` | SG | SGD |
| `amazon.ie` | IE | EUR | `amazon.com.tr` | TR | TRY |
| `amazon.se` | SE | SEK | `amazon.ae` | AE | AED |
| `amazon.pl` | PL | PLN | `amazon.sa` | SA | SAR |

**How `localeStrategy` changes behaviour, option by option.**

- `native` (default) — each storefront receives `i18n-prefs=<its currency>; lc-main=<its lc-main>; sp-cdn=L5Z9:<its country>; x-cdn=Cloudfront` and that storefront's own `Accept-Language`. This is the pairing that makes `amazon.de` quote euros. A `contentLanguage` pick does not change the cookie or the header in this mode — it only adds `?language=` to the URL, which switches page text while leaving the currency signal intact. A domain outside the map gets no cookie.
- `forceUsd` — every storefront receives `i18n-prefs=USD; lc-main=en_US; sp-cdn=L5Z9:US; x-cdn=Cloudfront`, so Amazon performs its own conversion and non-US storefronts answer in USD. Useful only when you specifically want Amazon's conversion; `priceIsNativeCurrency` reads `false` on those rows.
- `noLocaleCookie` — no locale cookie at all; Amazon decides from the exit IP. `Accept-Language` follows your `contentLanguage` if you set one, otherwise the storefront's own.
- Any other value is logged as unknown and treated as `native`.

**Where the USD figures come from.** With `convertPricesToUsd` on, the Actor makes one request at the start of the run to a keyless exchange-rate endpoint that the source identifies as an ECB reference feed (`api.frankfurter.app`, base USD). That single rate set is reused for every row in the run — rates are not refetched per storefront, per ASIN or per row. `fxRateToUsd` is the rate applied, and `fxRatesDate` is the date the feed itself reports for that set, which can be earlier than your run date; read it rather than assuming the number is intraday. `priceUsd` is `priceValue` divided by `fxRateToUsd`, rounded to four decimals.

Nothing is ever overwritten: `priceValue`, `priceCurrency`, `currencyCode` and `marketplaceCurrency` always keep the storefront's own figures, and `priceUsd` is an added column. If the feed is unreachable, returns a non-200, or publishes no rate for a row's currency, then `priceUsd` and `fxRateToUsd` come back `null` and the ranking falls back to same-currency storefronts only — the Actor never substitutes an invented rate. Treat `priceUsd` as a ranking aid, not a quotation: it is a daily reference rate, not the rate Amazon, a payment processor or a card issuer would apply, and the Actor performs no verification of the feed beyond the date the feed itself reports.

#### Example input

```json
{
  "asins": [
    "B07GBZ4Q68",
    "https://www.amazon.com/dp/B0CJ4V4TRP"
  ],
  "marketplaces": [
    "amazon.com",
    "amazon.de",
    "amazon.co.uk"
  ],
  "contentLanguage": "",
  "localeStrategy": "native",
  "convertPricesToUsd": true,
  "skipUnavailableStorefronts": false,
  "includeRichContent": false,
  "deliveryPostalCode": "10115",
  "exitCountry": "MARKETPLACE_MATCH",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

That input produces six rows: two ASINs across three storefronts.

### ⬆️ Output

Every ASIN-storefront pair is one dataset row. A parsed row carries the same 85 keys run after run, nested objects keep a fixed shape, and unfound values come back as `null` or as an empty list rather than under a renamed key. Export as JSON, CSV or Excel, or read the dataset through the Apify API. The run also writes an `OUTPUT` record to the default key-value store — the same rows nested as `{ asin: { marketplace: row } }` — which is convenient when you want the matrix rather than a flat table.

#### Example output

```json
{
  "asin": "B07GBZ4Q68",
  "originalAsin": "B07GBZ4Q68",
  "marketplace": "amazon.de",
  "marketplaceCountry": "DE",
  "marketplaceCurrency": "EUR",
  "priceValue": 35.29,
  "priceCurrency": "€",
  "currencyCode": "EUR",
  "priceIsNativeCurrency": true,
  "price": { "value": 35.29, "currency": "€" },
  "listPrice": { "value": 44.99, "currency": "€" },
  "priceRange": null,
  "priceUsd": 41.0731,
  "fxRateToUsd": 0.8592,
  "fxRatesDate": "2026-07-24",
  "priceComparisonBasis": "usd_ecb_reference",
  "priceRank": 1,
  "isCheapestMarketplace": true,
  "cheapestMarketplace": "amazon.de",
  "cheapestPriceUsd": 41.0731,
  "priceGapPercent": 0.0,
  "marketplacesCompared": 3,
  "marketplacesPriced": 3,
  "isAvailable": true,
  "availabilityStatus": "in_stock",
  "inStock": true,
  "inStockText": "Auf Lager",
  "title": "Logitech G502 HERO High Performance Gaming-Maus mit HERO 25K DPI Sensor, RGB",
  "brand": "Logitech G",
  "author": null,
  "description": "Der HERO 25K Sensor ist der leistungsstärkste Gaming-Sensor von Logitech.",
  "bookDescription": null,
  "features": [
    "HERO 25K Sensor mit bis zu 25.600 DPI",
    "11 programmierbare Tasten",
    "Anpassbares Gewichtssystem mit fünf 3,6-g-Gewichten"
  ],
  "attributes": [
    { "key": "Marke", "value": "Logitech G" },
    { "key": "Verbindungstechnologie", "value": "Kabelgebunden" },
    { "key": "Artikelgewicht", "value": "121 g" }
  ],
  "productOverview": [
    { "key": "Marke", "value": "Logitech G" },
    { "key": "Farbe", "value": "Schwarz" }
  ],
  "breadCrumbs": "Computer & Zubehör > Zubehör > Mäuse",
  "thumbnailImage": "https://m.media-amazon.com/images/I/61mpMH5TzkL._AC_SL1500_.jpg",
  "galleryThumbnails": [],
  "highResolutionImages": [],
  "videosCount": 2,
  "variantAsins": ["B07GBZ4Q68", "B07GCKQD77"],
  "variantDetails": [
    {
      "name": "Schwarz",
      "thumbnail": "https://m.media-amazon.com/images/I/31Y4a2mS9lL._SS36_.jpg",
      "images": ["https://m.media-amazon.com/images/I/31Y4a2mS9lL._SS36_.jpg"],
      "asin": "B07GCKQD77",
      "price": { "value": 39.99, "currency": null }
    }
  ],
  "variantAttributes": [{ "key": "Farbe", "value": "Schwarz" }],
  "stars": 4.6,
  "starsBreakdown": { "5star": 0.81, "4star": 0.11, "3star": 0.04, "2star": 0.01, "1star": 0.03 },
  "reviewsCount": 55283,
  "hasReviews": true,
  "reviewsLink": "https://www.amazon.de/product-reviews/B07GBZ4Q68",
  "answeredQuestions": null,
  "monthlyPurchaseVolume": "1.000+ Mal im letzten Monat gekauft",
  "bestsellerRanks": [
    {
      "rank": 3,
      "category": "PC-Mäuse",
      "url": "https://www.amazon.de/gp/bestsellers/computers/430168031",
      "categoryNodeId": "430168031"
    }
  ],
  "isAmazonChoice": true,
  "amazonChoiceText": "Amazon's Choice for \"gaming maus\"",
  "seller": {
    "name": "Amazon",
    "id": null,
    "url": "https://www.amazon.com",
    "reviewsCount": null,
    "averageRating": null
  },
  "shipsFrom": "Amazon",
  "shippingPrice": { "value": 0.0, "currency": "€" },
  "delivery": "Donnerstag, 30. Juli",
  "fastestDelivery": "Mittwoch, 29. Juli",
  "condition": "New",
  "returnPolicy": "Rückgabe innerhalb von 30 Tagen ab Erhalt",
  "support": null,
  "importantInformation": null,
  "sustainabilityFeatures": null,
  "aPlusContent": null,
  "brandStory": null,
  "productComparison": null,
  "aiReviewsSummary": null,
  "url": "https://www.amazon.de/gp/product/B07GBZ4Q68?smid=",
  "unNormalizedProductUrl": "https://www.amazon.de/dp/B07GBZ4Q68",
  "input": "https://www.amazon.de/dp/B07GBZ4Q68",
  "visitStoreLink": "https://www.amazon.de/stores/LogitechG/page/1234ABCD",
  "locationText": "Lieferung nach 10115",
  "loadedCountryCode": "DE",
  "pageLanguageTag": "de-de",
  "localeStrategy": "native",
  "localeCookieSent": "i18n-prefs=EUR; lc-main=de_DE; sp-cdn=L5Z9:DE; x-cdn=Cloudfront",
  "buyBoxDegraded": false,
  "hasCorePriceDisplay": true,
  "fetchOutcome": "ok",
  "httpStatus": 200,
  "responseBytes": 1728431,
  "usedProxy": true,
  "proxyCountryUsed": "DE",
  "position": 1,
  "scrapedAt": "2026-07-25T09:14:02Z"
}
```

The rich-content keys read `null` above because the example input set `includeRichContent: false`. With it on, `aPlusContent` returns `{ "title", "rawText", "rawImages", "rawVideos", "modules" }`, `brandStory` returns `{ "title", "image", "items" }`, `productComparison` returns `{ "products": [...] }`, and `aiReviewsSummary` returns `{ "text", "keywords" }`.

#### Rows where the product could not be read

When a storefront returns 404/410, a block, a transport failure or an unparseable page, the row is still written — with `error` present and the product fields absent rather than nulled:

```json
{
  "asin": "B0CJ4V4TRP",
  "originalAsin": "B0CJ4V4TRP",
  "marketplace": "amazon.co.uk",
  "marketplaceCountry": "GB",
  "marketplaceCurrency": "GBP",
  "priceValue": null,
  "priceCurrency": null,
  "currencyCode": null,
  "price": null,
  "title": null,
  "url": "https://www.amazon.co.uk/dp/B0CJ4V4TRP",
  "error": "not_listed",
  "isAvailable": false,
  "availabilityStatus": "not_listed_in_marketplace",
  "fetchOutcome": "not_listed",
  "httpStatus": 404,
  "responseBytes": 0,
  "usedProxy": true,
  "proxyCountryUsed": "GB",
  "scrapedAt": "2026-07-25T09:14:02Z",
  "priceUsd": null,
  "fxRateToUsd": null,
  "fxRatesDate": "2026-07-24",
  "priceComparisonBasis": "usd_ecb_reference",
  "priceRank": null,
  "priceGapPercent": null,
  "isCheapestMarketplace": null,
  "cheapestMarketplace": "amazon.de",
  "cheapestPriceUsd": 41.0731,
  "marketplacesCompared": 3,
  "marketplacesPriced": 2
}
```

**Charged and uncharged rows.** The Actor bills a `row_result` event per row and does not bill rows it could not read. A row is charged when `fetchOutcome` is `ok` or `not_listed` — a confirmed absence is a real answer, so it is billed like any other row. Rows with `fetchOutcome` of `blocked`, `fetch_failed` or `parse_error` are pushed to the dataset **uncharged**. There is no separate error-marker field beyond `fetchOutcome` and the `error` key, so filter on that:

```python
charged = [r for r in rows if r["fetchOutcome"] in ("ok", "not_listed")]
free    = [r for r in rows if r["fetchOutcome"] not in ("ok", "not_listed")]
```

### How does it work?

Each ASIN-storefront pair is one HTTP request to `https://www.<domain>/dp/<ASIN>`, sent through an Apify Residential exit in that storefront's own country, carrying that storefront's locale cookie and `Accept-Language` plus a desktop browser header set. When you supply a postal code, the Actor first walks Amazon's delivery-address flow on each storefront to collect a location cookie and replays it on the product requests.

Responses are validated before parsing: a body smaller than a real product page, or one containing CAPTCHA markers, is treated as a block and triggers a retry on a fresh session, with a final attempt made without any proxy. Parsing then reads both the rendered page and the JSON blocks Amazon embeds in it — image sets, variant maps, A+ video URLs — using several candidate selectors per field and falling back rather than failing, so a layout change degrades one field instead of the row. Prices are only accepted from inside the product's own buy-box containers, never from a recommendation carousel, so a neighbouring product's price cannot be reported as this ASIN's.

Only publicly visible product data is collected. Field names and types are held stable across Actor updates, so an integration reading `priceValue` and `cheapestMarketplace` keeps working when Amazon changes its front end.

### Integrations

Amazon ASIN Scraper By Country & Marketplace is an Apify Actor, so it works with anything that can call the Apify API or consume a dataset — schedules, webhooks, storage exports and no-code automation platforms.

#### Calling it from Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("<YOUR_USERNAME>/amazon-asin-scraper-by-country-marketplace").call(run_input={
    "asins": ["B07GBZ4Q68", "B0CJ4V4TRP"],
    "marketplaces": ["amazon.com", "amazon.de", "amazon.co.uk"],
    "localeStrategy": "native",
    "convertPricesToUsd": True,
    "includeRichContent": False,
    "exitCountry": "MARKETPLACE_MATCH",
})

rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())

for r in sorted(rows, key=lambda x: (x["asin"], x.get("priceRank") or 99)):
    print(r["asin"], r["marketplace"], r.get("priceValue"), r.get("currencyCode"),
          r.get("priceUsd"), r.get("priceGapPercent"), r["availabilityStatus"])
```

Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request.

#### No-code tools (n8n, Make, Zapier)

In n8n, use the Apify node — or an HTTP Request node pointed at the Actor's run endpoint with your token — and pass the same JSON input shown above. In Make, use the Apify module and map the dataset rows straight into a Google Sheets or Airtable step, keying on `asin` plus `marketplace` so a repeat run updates rather than duplicates. Both handle scheduling, so a daily cross-market price sweep needs no code at all.

### Is it legal to scrape Amazon product listings?

Scraping publicly listed product data is broadly treated as permissible where the data is accessible without authentication, and this Actor collects only what an anonymous visitor already sees on a country's product page — no account, no login, no session.

Prices, availability, titles, ratings and bestseller ranks are commercial business records, not personal data. The personal-data regimes that govern profile scraping — GDPR and its equivalents — do not attach to this output the way they would to a scraper that collects people. The obligations that do apply are contractual and database-related: Amazon's terms of service restrict automated access, which is a civil and contractual matter rather than a criminal one, and local database or unfair-competition rules can apply if you systematically reproduce a substantial part of Amazon's catalogue as a competing listing.

One narrow exception is worth naming: `seller.name` carries the buy-box merchant's trading name, and a small independent trader's trading name is sometimes their personal name. If you store that field at scale, treat it accordingly.

Consult legal counsel before republishing extracted listings as a competing catalogue, or before reselling the data as a standalone product.

### ❓ Frequently asked questions

#### What Amazon fields does Amazon ASIN Scraper By Country & Marketplace return?

The five that matter most for cross-market work are `priceValue`, `currencyCode`, `priceUsd`, `cheapestMarketplace` and `isAvailable`. A parsed row carries 85 keys in total, including `priceRank`, `priceGapPercent`, `priceIsNativeCurrency`, `stars`, `reviewsCount`, `bestsellerRanks` and the full product record — see the data fields table above.

#### Does it require an Amazon account or login?

No. No Amazon account, no login, no cookie of your own, and no Product Advertising API approval. The only credential you need is your Apify token.

#### How many rows will one run produce, and can I compare many ASINs at once?

Yes, and the arithmetic is exact: one row per ASIN per marketplace. Ten ASINs across five storefronts is fifty rows. `asins` and `marketplaces` are both lists with no Actor-imposed cap, and entries are split on whitespace, commas and semicolons then deduplicated, so a pasted block works. The only thing that changes the count is `skipUnavailableStorefronts`, which removes rows.

#### What happens if an ASIN does not exist in a given marketplace, or is unavailable there?

You still get a row, and the two cases are distinguishable. A storefront that answers 404 or 410 produces `isAvailable: false` with `availabilityStatus: "not_listed_in_marketplace"`, `fetchOutcome: "not_listed"` and an `error` key of `"not_listed"` — the ASIN is simply not sold in that country. An ASIN that is listed but out of stock produces `isAvailable: false` with `availabilityStatus: "out_of_stock"` and a full product record. A page that was blocked or failed in transport produces `isAvailable: null` with an `unknown_*` status and is not charged — never `false`, because "we could not tell" and "not sold here" are opposite conclusions. Filter on `availabilityStatus`, not on a null price.

#### Where do the USD prices come from, and can I trust them?

From one request per run to a keyless exchange-rate endpoint that the Actor's source identifies as an ECB reference feed, with USD as the base. The whole run shares that single rate set; `fxRateToUsd` is the rate applied to a row, and `fxRatesDate` is the date the feed reports for it, which may be earlier than your run. Trust it for **ranking** storefronts against each other, which is what it exists for. Do not treat it as a quotation — it is a daily reference rate, not Amazon's conversion and not a card issuer's. The storefront's own `priceValue`, `priceCurrency` and `currencyCode` are always preserved alongside it, and if the feed is unreachable or carries no rate for that currency, `priceUsd` and `fxRateToUsd` are `null` and the ranking falls back to same-currency comparison — an invented rate is never substituted. `priceComparisonBasis` on every row tells you which of those happened.

#### Why is a non-US price coming back in USD?

Check `localeStrategy` and `priceIsNativeCurrency`. Under `forceUsd`, Amazon is asked to convert and will answer non-US storefronts in USD by design. Under `native`, each storefront gets its own currency cookie; if `priceIsNativeCurrency` is still `false`, compare `currencyCode` with `marketplaceCurrency`, then read `localeCookieSent` and `pageLanguageTag` on that row to see exactly what was sent and what Amazon served back.

#### Does it work with Claude, ChatGPT and other AI agent tools?

Yes. It is callable as a standard HTTP endpoint through the Apify API, so any agent framework that can make a request — LangChain, CrewAI, n8n or a custom tool definition — can invoke it and receive typed JSON directly.

#### How does it compare to other Amazon ASIN scrapers?

Checked on the Apify Store on 25 July 2026. `junglee/amazon-asins-scraper` is the most-used ASIN Actor by a wide margin and documents ASIN input with a store selector plus a clear error-item contract and error-code table; its README describes one Amazon store per run, and per-row cross-marketplace comparison is not documented. `jaybird/amazon-product-data-scraper` takes product URLs from any Amazon domain, returns one record per URL and documents an `includeNotFound` switch for dead listings; cross-storefront ranking is not documented. `viralanalyzer/amazon-multi-country` is the closest in intent — it documents seven marketplaces with locale-correct decimal parsing and per-country Prime filters — but it is keyword-search or URL driven, and a per-row cheapest-marketplace or USD-normalised rank is not documented. Where this Actor differs is that the comparison *is* the output: one ASIN list fans out across your storefronts, and every row carries `priceRank`, `cheapestMarketplace`, `priceGapPercent`, `priceIsNativeCurrency`, `priceComparisonBasis` and a three-valued `isAvailable`. Capabilities not stated in a competitor's README are described as "not documented" rather than assumed absent.

#### Does it return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with the same key names on every run — no HTML, no selectors. Pass a row straight into a context window, index it into a vector store, or hand it to an agent tool. The `OUTPUT` key-value record additionally gives you the ASIN-by-marketplace matrix if that shape suits your prompt better than a flat table.

#### What happens when Amazon changes its layout or anti-bot system?

The Actor is maintained, and it is built to degrade rather than break: each field is read through a chain of candidate selectors with Amazon's embedded page data as a fallback, so a redesign usually costs one field rather than the row. Blocking is detected by response size instead of status code, which is what catches Amazon's HTTP 200 CAPTCHA shells. Your field names and types do not change on your end.

#### Can I use it without managing proxies or browser infrastructure?

Yes. Leave `proxyConfiguration` and `exitCountry` alone and the Actor runs on Apify Residential with the exit country pinned to each storefront, creates and rotates its own sessions, retries with backoff, and makes a final unproxied attempt when it has seen a block. There is no browser to run — requests are plain HTTP. There is no CAPTCHA solver, and the legacy `useCaptchaSolver` input is a logged no-op.

#### Which fields work best for AI training data and RAG indexing?

For RAG: `title`, `description`, `features` and `attributes` carry the most descriptive text per row and chunk cleanly, with `marketplace` and `pageLanguageTag` as the locale dimension so a retrieved chunk stays attributable to a country. For training data: `priceValue`, `priceUsd`, `currencyCode`, `priceRank`, `priceGapPercent`, `stars`, `reviewsCount` and `isAvailable` are the most structurally consistent fields across records. All of them arrive as typed primitives, so no normalization pass is needed before indexing.

### 🔗 Related scrapers

| Scraper Name | What it extracts |
| ----- | ----- |
| Amazon Product Scraper By Bestseller & Demand Filter | Products from category or product URLs, filtered on monthly purchases and bestseller rank |
| Amazon Today's Deals Scraper With Star Ratings & Deal Badges | Today's Deals listings with deal badges, savings and star histograms |
| Amazon Top Rated Products Scraper | Keyword-search results filtered by minimum rating and review count, with review insights |
| Alibaba Scraper | B2B product listings with prices, MOQ and supplier trust data |

Pick by the job: this Actor when you already know the ASINs and need them priced country by country; the bestseller and demand filter when you are still discovering which products matter; Today's Deals when the discount surface is the target; Top Rated when you are searching by keyword and thresholding on ratings.

### 💬 Your feedback

Found a bug, or need a storefront that is not in the built-in locale map? Open an issue on the Actor's Issues tab and it will be looked at. Reports that include the ASIN, the domain, and the `fetchOutcome` and `proxyCountryUsed` values from the affected row are the fastest to act on.

# Actor input Schema

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

One ASIN per line. Full product URLs work too — `https://www.amazon.com/dp/B07GBZ4Q68` and `/gp/product/…` links are reduced to their ASIN automatically.

The ASIN sits in the URL right after `/dp/`.

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

Domains to price each ASIN on, e.g. `amazon.com`, `amazon.de`, `amazon.co.uk`, `amazon.fr`, `amazon.it`, `amazon.es`, `amazon.ca`, `amazon.com.au`, `amazon.co.jp`, `amazon.in`, `amazon.com.mx`, `amazon.com.br`, `amazon.nl`, `amazon.se`, `amazon.pl`, `amazon.sg`, `amazon.ae`.

Example: 2 ASINs × 3 storefronts → 6 rows. Leave empty for `amazon.com` only.

## `contentLanguage` (type: `string`):

Leave on **Storefront native** so each country's page renders in its own language — that is what keeps prices in the local currency.

Pick a language only if you need every storefront's text in one tongue.

## `localeStrategy` (type: `string`):

**Storefront local currency** (recommended): each domain gets its own `i18n-prefs`/`lc-main` cookie, so amazon.de returns `35,29 €` and amazon.co.uk `£29.99`.

**Force USD everywhere**: reproduces the old behaviour — Amazon converts, and amazon.de answers `USD40.38` with no € on the page. Useful only if you deliberately want Amazon's own conversion.

**Send no locale cookie**: let Amazon decide from the exit IP.

## `convertPricesToUsd` (type: `boolean`):

Pulls ECB reference rates once per run and fills `priceUsd`, `fxRateToUsd` and `fxRatesDate`, so storefronts in different currencies can be ranked against each other.

If the rate source is unreachable these stay `null` and ranking falls back to same-currency storefronts only — never an invented rate. Default: on.

## `skipUnavailableStorefronts` (type: `boolean`):

On: rows where `isAvailable` is not `true` (not listed in that country, out of stock, or undetermined) are left out entirely.

Off (default): they are kept, so you can see *where* an ASIN is missing — that absence is usually the point.

## `includeRichContent` (type: `boolean`):

These blocks dominate the record size and are identical across storefronts. Turn off for a lean price-comparison dataset — the keys stay present, just emptied. Default: on.

## `deliveryPostalCode` (type: `string`):

Example: `10001` (US) or `10115` (Berlin). Applied to every storefront via Amazon's delivery-address cookie before scraping. Leave blank to use each marketplace's default.

## `exitCountry` (type: `string`):

**Match each storefront** (recommended) routes amazon.de through a German IP, amazon.co.uk through a British one, and so on.

⚠️ A US exit against a non-US Amazon domain is answered with a ~3.8 KB CAPTCHA shell, so a country that contradicts the storefront is overridden and the substitution is reported in the `proxyCountryUsed` column.

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

Overrides the exit-country selector above. With your own `proxyUrls` the geo decision is entirely yours — mismatched countries are no longer corrected.

## Actor input object example

```json
{
  "asins": [
    "B07GBZ4Q68",
    "B0CJ4V4TRP"
  ],
  "marketplaces": [
    "amazon.com",
    "amazon.de",
    "amazon.co.uk"
  ],
  "contentLanguage": "",
  "localeStrategy": "native",
  "convertPricesToUsd": true,
  "skipUnavailableStorefronts": false,
  "includeRichContent": true,
  "deliveryPostalCode": "",
  "exitCountry": "MARKETPLACE_MATCH",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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": [
        "B07GBZ4Q68",
        "B0CJ4V4TRP"
    ],
    "marketplaces": [
        "amazon.com",
        "amazon.de",
        "amazon.co.uk"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper-engine/amazon-asins-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": [
        "B07GBZ4Q68",
        "B0CJ4V4TRP",
    ],
    "marketplaces": [
        "amazon.com",
        "amazon.de",
        "amazon.co.uk",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scraper-engine/amazon-asins-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "B07GBZ4Q68",
    "B0CJ4V4TRP"
  ],
  "marketplaces": [
    "amazon.com",
    "amazon.de",
    "amazon.co.uk"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scraper-engine/amazon-asins-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=scraper-engine/amazon-asins-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/SkxJIVUdpa8zbpZ3O/builds/D1QVXe7bsqvwf9oWn/openapi.json
