# Amazon Search Scraper (`usestring/amazon-search`) Actor

Runs keyword searches on Amazon and returns the whole first results page in order: rank, ASIN, title, numeric price, currency, rating, review count and an isSponsored flag on ad placements. Starts from a keyword, not a known ASIN. Seven marketplaces, each searched in its own language.

- **URL**: https://apify.com/usestring/amazon-search.md
- **Developed by:** [String](https://apify.com/usestring) (community)
- **Categories:** E-commerce, Business
- **Features:** Limited permissions
- **Stats:** 2 total users, 0 monthly users, 96.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Amazon Search Scraper do?

It runs keyword searches on Amazon and returns every product on the first results page in the order
it appeared, one row each: on-page `rank`, `asin`, `title`, a **numeric** `price` with its
`currency`, `rating`, `reviewCount`, `imageUrl` and an `isSponsored` flag marking the paid
placements.

Of our three Amazon Actors, this is the discovery one. It is the only one that starts from a
keyword: [Amazon Product Scraper](https://apify.com/usestring/amazon-products) needs ASINs you
already hold, and [Amazon Bestsellers
Scraper](https://apify.com/usestring/amazon-bestsellers) starts from a category slug. Search is the
Actor to reach for when the question is "who shows up for this term, in what order, at what price"
— including the ads, which are usually the point.

- `rank` is the position on the page with ad placements counted in their real slots, and
  `isSponsored` tells you which rows those are. Organic rank and sponsored share both fall out of
  the same dataset.
- Up to 50 keywords per run, one results page each, roughly 22 rows per keyword.
- Seven marketplaces: US, UK, Germany, France, Spain, Japan and Australia.
- Each search is pinned to an exit in its own country and carries Amazon's own language parameter,
  so a German search returns German titles and euro prices.
- The review count is the exact figure where the page carries one, not the rounded `8.1K` badge.

No Amazon account, API key or cookies are involved. Median of about 3.4 seconds per search in our
own measurements.

### What data does it extract?

| Field | Type | Description |
| --- | --- | --- |
| `query` | string | The search term this row came from, echoed onto every row |
| `rank` | number | Position on the results page, 1-based, **ads counted in place** |
| `asin` | string | Amazon's ten-character product ID. Feed it straight to the Amazon Product Scraper |
| `title` | string | The product title, not the brand line that sits above it in Amazon's elevated grid layout |
| `price` | number | `24.99`, not `"$24.99"` |
| `priceText` | string | The price as the storefront printed it, grouping and symbol included |
| `currency` | string | ISO code read from what the page actually printed: `USD`, `GBP`, `EUR`, `JPY`, `AUD` |
| `rating` | number | Stars out of 5, with locale decimal commas handled — `4,5 von 5` on amazon.de is `4.5` |
| `reviewCount` | number | Exact where the page states it exactly: `8157` rather than `8.1K` |
| `isSponsored` | boolean | `true` for an ad placement |
| `imageUrl` | string | The result thumbnail |
| `marketplace` | string | `us`, `uk`, `de`, `fr`, `es`, `jp` or `au` |
| `sourceUrl` | string | The search URL that was fetched |
| `collectedAt` | string | ISO timestamp stamped once per run |

A result with no visible price returns `price`, `priceText` and `currency` as `null` rather than
zero, which matters more than it sounds: ad tiles are the rows most likely to omit a price.

#### How the page is read

A search page carries no state blob and runs 1.2 to 2.5MB, so the result grid is parsed directly.
Two details are worth knowing because they show up in the data:

Each result element is sliced by balancing its `<div>` tags rather than by cutting at the next
result. Amazon injects comparison tables, brand carousels and a page footer between rows; cutting at
the next result folds all of that into whichever row precedes it, and a neighbour's price then leaks
into a row that has none of its own.

Sponsored rows are detected from markup classes, not from the visible "Sponsored" label. The label
is translated on every non-English storefront, and the accessibility text with it, so a
label-matching detector quietly returns `isSponsored: false` everywhere outside the US and UK. The
class names do not move.

### Geography, language and currency

`marketplace` sets three things at once, and all three are load-bearing:

- **The exit country.** The search is fetched from inside that country. This settles the currency
  and, on some storefronts, whether an ad tile carries a price at all.
- **The language.** Amazon's own `language` parameter rides the search URL, which is what actually
  switches the copy. An `Accept-Language` header measurably does not, which is why the parameter is
  used instead. A `de` search returns German titles.
- **The currency fallback.** `currency` is read from the symbol or ISO code the page printed. Where
  a price prints a bare `$`, ambiguous between the US and Australian storefronts, the marketplace
  settles it.

So the same keyword on `us` and `de` gives you two different result sets in two languages and two
currencies, which is the honest answer — Amazon genuinely ranks and prices them differently. Nothing
is translated or converted on the way out.

### Why scrape Amazon search results?

- **Keyword rank tracking.** Run your terms daily, filter to your own ASINs, and you have the rank
  history that Seller Central will not give you for competitors.
- **Ad-share measurement.** Count `isSponsored` rows on page one and you know how much of the term
  is being bought rather than earned, before you bid on it.
- **Competitor discovery.** The ASINs ranking for the terms you sell against are the shortlist worth
  enriching with the product Actor.
- **Price benchmarking.** Numeric prices across a keyword's whole first page give you the actual
  price band a shopper sees, not the band you assume.
- **Market entry checks.** The same keyword across seven storefronts shows where a category is
  crowded and where it is thin.

### How to use it

1. Open the Actor and click **Try for free**.
2. Put your keywords in **Search terms**, one per line, up to 50.
3. Pick a **Marketplace**. One marketplace per run — to compare storefronts, run the same keyword
   list once per marketplace, since every row carries its own `marketplace` and the datasets
   concatenate cleanly.
4. Set **Maximum results** and **Concurrency** to taste.
5. Run it, then export the dataset as JSON, CSV or Excel, or read it through the API. The `SUMMARY`
   record lists any query that failed, with the reason.

### Input

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `queries` | array of strings | required | Keywords to search, 1 to 50 per run |
| `marketplace` | string | `us` | One of `us`, `uk`, `de`, `fr`, `es`, `jp`, `au` |
| `maxItems` | integer | `1000` | Ceiling on dataset rows, 1 to 50,000 |
| `concurrency` | integer | `5` | Searches fetched in parallel, 1 to 10 |

```json
{
  "queries": ["wireless earbuds", "usb c charger", "standing desk"],
  "marketplace": "us",
  "maxItems": 1000,
  "concurrency": 5
}
```

Duplicate keywords collapse before anything is fetched. Search operators and filters are not
supported: the keyword goes into Amazon's `k` parameter as typed, and no department restriction,
sort order or price filter is applied on top.

### Output

One row per search result. This is the shape rather than a captured run:

```json
[
  {
    "query": "wireless earbuds",
    "rank": 1,
    "asin": "B0C33XXS56",
    "title": "Wireless Earbuds Bluetooth 5.3 Headphones with Charging Case",
    "price": 24.99,
    "priceText": "$24.99",
    "currency": "USD",
    "rating": 4.3,
    "reviewCount": 8157,
    "isSponsored": true,
    "imageUrl": "https://m.media-amazon.com/images/I/61jT4tGqNBL._AC_UL320_.jpg",
    "marketplace": "us",
    "sourceUrl": "https://www.amazon.com/s?k=wireless%20earbuds&language=en_US",
    "collectedAt": "2026-08-20T09:14:02.881Z"
  },
  {
    "query": "wireless earbuds",
    "rank": 2,
    "asin": "B0CHX3QBCH",
    "title": "Apple AirPods Pro 2 Wireless Earbuds, USB-C Charging Case",
    "price": 189.99,
    "priceText": "$189.99",
    "currency": "USD",
    "rating": 4.7,
    "reviewCount": 108442,
    "isSponsored": false,
    "imageUrl": "https://m.media-amazon.com/images/I/61SUj2aKoEL._AC_UL320_.jpg",
    "marketplace": "us",
    "sourceUrl": "https://www.amazon.com/s?k=wireless%20earbuds&language=en_US",
    "collectedAt": "2026-08-20T09:14:02.881Z"
  }
]
```

### How much does it cost?

Pay-per-event: you are charged per result row written to the dataset. Rows are only written when
they can be charged, so reaching your spend limit stops the run writing rather than delivering
unbilled rows. The per-row figure is on the Actor's Store page, where it stays current.

Runs started from an Apify **free plan** stop at **250 requests and 250 results**, with a status
message saying so. Any paid plan runs the full input and the `maxItems` you set. Because a keyword
yields roughly 22 rows, a free run is bounded by rows long before it is bounded by keywords.

The limit exists because this Actor fetches through our own scraping infrastructure, which Apify
does not cover for free-plan runs. It binds on requests as well as rows so that a long keyword list
cannot spend fetches on rows the run will not return.

### Using it with the Apify API

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('usestring/amazon-search').call({
  queries: ['wireless earbuds', 'usb c charger'],
  marketplace: 'de',
  maxItems: 500
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
const sponsored = items.filter((item) => item.isSponsored).length;
console.log(`${sponsored} of ${items.length} rows are ads`);
```

The Python client and the REST API expose the same run, and a schedule turns this into a daily rank
snapshot without further work.

### Limitations

One results page per keyword. There is no pagination into page two, no sort order, no department or
price filtering, and no search-operator support. Rows carry only what the grid shows, so there is no
description, availability, seller or variant data — run the returned ASINs through the Amazon
Product Scraper for those. Marketplaces beyond the seven listed above, amazon.in included, are not
supported. Rankings are the page as it stood at `collectedAt`, and Amazon's results vary over time
and by shopper.

### Related actors

- [Amazon Product Scraper](https://apify.com/usestring/amazon-products) — the natural second step:
  the ASINs from these rows become full detail records.
- [Amazon Bestsellers Scraper](https://apify.com/usestring/amazon-bestsellers) — category rankings
  instead of keyword rankings, for demand you cannot phrase as a search term.
- [Walmart Product Scraper](https://apify.com/usestring/walmart-products) — check whether the
  products you found here are also on Walmart, and at what price.
- [Home Depot Product Scraper](https://apify.com/usestring/homedepot-products) — the same price and
  stock work for home-improvement SKUs.
- [Etsy Listings Scraper](https://apify.com/usestring/etsy-listings) — keyword-driven listing
  research on the handmade marketplace.

### FAQ

**How many results does one keyword return?**
Roughly 22 — one Amazon results page. The Actor does not paginate, so one keyword is one fetch and
one page of rows.

**Are sponsored products included?**
Yes, and they are labelled. `isSponsored` marks them and `rank` counts them in the slot they
occupy, because where an ad sits is usually the thing being measured. Filter them out afterwards if
you want organic-only rank.

**Can I search several marketplaces in one run?**
Not in one run — `marketplace` is a single choice. Run the same keyword list once per marketplace;
every row carries its `marketplace`, so the datasets combine without extra work.

**Can I use search filters, a sort order or a department?**
No. The keyword is sent as typed, and Amazon's default relevance ordering is what you get.

**Is the price a number?**
Yes. `price` is numeric, `priceText` keeps the original formatting, and `currency` is read from what
the page printed rather than assumed from the storefront.

**What happens to a query that fails?**
It is recorded under `failures` in the run's `SUMMARY` record with the URL and the reason, and the
other queries still return their rows. If every query fails, the run fails rather than reporting an
empty success.

### Feedback

Found a keyword that parses badly, or a marketplace behaving oddly? Open an issue from the Actor's
Store page with the exact query and marketplace, and it can be reproduced in a single run.

# Actor input Schema

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

Keywords to search on Amazon.

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

Amazon marketplace to search.

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

Global cap on dataset items. Runs started from an Apify free plan stop at 250 requests and 250 results; any paid plan runs the full amount.

## `concurrency` (type: `integer`):

Targets fetched in parallel.

## Actor input object example

```json
{
  "queries": [
    "wireless earbuds"
  ],
  "marketplace": "us",
  "maxItems": 1000,
  "concurrency": 5
}
```

# Actor output Schema

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

Runs keyword searches on Amazon and returns the whole first results page in order: rank, ASIN, title, numeric price, currency, rating, review count and an isSponsored flag on ad placements. Starts from a keyword, not a known ASIN. Seven marketplaces, each searched in its own language.

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

Item count, failure count and every target that failed, with its error.

# 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 = {
    "queries": [
        "wireless earbuds"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("usestring/amazon-search").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 = { "queries": ["wireless earbuds"] }

# Run the Actor and wait for it to finish
run = client.actor("usestring/amazon-search").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 '{
  "queries": [
    "wireless earbuds"
  ]
}' |
apify call usestring/amazon-search --silent --output-dataset

```

## MCP server setup

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

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/lciI2HFIkMcgEQWhS/builds/Y7iyf7MFwg9pM5bgo/openapi.json
