# Amazon Sponsored Products Scraper - Ads by Keyword (`automation_craft/amazon-sponsored-products-scraper`) Actor

Scrape every paid placement on Amazon search results for your keywords: Sponsored Products, sponsored carousels and Sponsored Brands, with ASIN, price, ad position, ad id and organic rank. 21 stores, EU advertiser and payer names. Export JSON, CSV or Excel via API. Pay per ad placement.

- **URL**: https://apify.com/automation_craft/amazon-sponsored-products-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** E-commerce, Marketing
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.59 / 1,000 ad placements

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

### Amazon Sponsored Products Scraper - Ads by Keyword

Scrape **Amazon sponsored products and sponsored ads by keyword**: every paid placement Amazon shows on the search result page for the keywords you give, one row each. Sponsored Products cards in the result grid, the products of sponsored carousels, the Sponsored Brands banner above the results, Sponsored Brands videos and collections, and the brands of "Brands related to your search", each with its position on the page, the advertised ASIN, title, price, rating and reviews, Amazon's own ad and campaign ids, and the organic rank of the same product when it also ranks without paying. In the EU stores it can add the advertiser and the payer Amazon names for each ad. 21 Amazon stores, pages 1 to 5, several samples per keyword for share of voice, no login and no cookies.

Every page is read from a residential address in the store's own country, because Amazon serves pages without their ads to datacenter addresses and, on amazon.com, to about a quarter of ordinary visits as well. A page that comes back with its Sponsored Products removed is read again and never billed, so "no ads" in your data means Amazon showed none, not that the scraper was shown a stripped page.

#### What a search result page holds

On a page 1 with ads Amazon shows 6 or 12 Sponsored Products cards between the organic results, usually two or three sponsored carousels ("Trending now", "Highly rated"), a Sponsored Brands banner, a Sponsored Brands video, three footer brands, and on amazon.com a sponsored "Shop by type" module: a median of 25 paid placements per page in testing (152 result pages, 3,592 placements, 2026-10-08). Amazon rotates its ads between page loads; the four top slots stay much the same, the rest changes.

### Quick start

1. Open the Actor and leave the prefilled input (`keywords: ["protein powder"]`, amazon.com, one page): the run returns page 1's placements in about ten seconds.
2. Put your own keywords into **Keywords or Amazon search URLs**, one per line, and choose the **Amazon store**. A pasted search URL (`https://www.amazon.de/s?k=proteinpulver&i=drugstore`) keeps its own store and its filters (category, brand, price, sort).
3. Raise **Result pages per keyword** (up to 5) for deeper slots, and **Samples per keyword** (up to 10) to see which products appear most often.
4. In an EU store, switch on **EU advertiser and payer names** to learn who is behind each ad.
5. Read the dataset as JSON, CSV or Excel, or call the Actor through the API (examples below). Schedule it to track a keyword day by day.

### What you get

One `placement` row per paid placement. Fill rates over the 3,592 placement rows (152 result pages) of the test runs of 2026-10-08 in amazon.com, .co.uk, .de, .co.jp, .in, .com.mx and .ae.

| Field | What it holds | Fill |
|---|---|---|
| `keyword`, `domain`, `marketplace`, `page`, `sample`, `searchUrl` | the search the row comes from | 100 percent |
| `amazonSearchedFor` | the query Amazon says it ran, when it corrected yours (amazon.de ran "qwxzvbn trelock" for "qwxzvbn trelmok") | set only when Amazon rewrote it |
| `placementType` | `sponsored_product`, `sponsored_products_carousel`, `shop_by_type`, `sponsored_brand`, `sponsored_brand_video`, `sponsored_brand_collection`, `sponsored_brand_footer` | 100 percent |
| `adPosition` | the placement's order among the paid placements of the page, from the top | 100 percent |
| `resultSlot` | for a Sponsored Products card: its slot among all result cards, organic ones included | 100 percent of Sponsored Products cards |
| `afterResultSlot`, `itemPosition`, `moduleTitle` | where a module sits (after which result), the product's place inside a carousel, the carousel's heading | 100 percent of carousel and module rows |
| `positionBand`, `widgetName`, `slotName` | top, middle or bottom, and Amazon's own names of the ad slot | band: 100 percent of cards, banners and footer brands |
| `asin`, `title`, `productUrl`, `image` | the advertised product | 100 percent of Sponsored Products cards, carousel products and videos; Shop by type products carry no image; banners carry their products' ASINs (99 percent) in `asins`, no title or image |
| `price`, `currency`, `listPrice`, `unitPrice` | the price shown, the struck through list price, the price per unit | price 99 to 100 percent of product placements; list price 66 to 77; unit price 22 to 27 |
| `rating`, `reviewCount`, `boughtPastMonth`, `badge` | as shown on the placement | rating and reviews 98 to 100 percent of cards and carousel products; videos carry a rating (98 percent) and no review count; Shop by type products carry neither |
| `brand`, `headline`, `logoUrl`, `storeUrl`, `videoUrl`, `asins` | Sponsored Brands placements: the brand, its headline, logo, store link, video and products | banner: brand 100, headline 97, logo 99, store link 51 percent; footer brands: brand 100, headline 15 percent |
| `adId`, `campaignId`, `sku`, `advertiserId` | Amazon's ids of the ad and its campaign | ad and campaign ids 99 to 100 percent |
| `organicRank`, `organicPage` | the product's rank among the organic results of the pages read for this sample, when it also ranks without paying | 17 percent of Sponsored Products cards |
| `advertiserName`, `payerName`, `advertiserSellerId`, `targeting` | EU stores, when asked: who advertised, who paid, the advertiser's seller account, and whether the search words, the location or past activity selected the ad | 81 percent of EU rows (footer brands and most banners carry no advertiser id) |
| `merchantId` | the seller of the offer shown on a card | 48 percent of cards |
| `timesShownOnPage`, `otherPositions` | an ad Amazon showed twice in the same kind of placement on one page is one row, with its other place listed | 100 percent |

Three more row types, all free. A `keyword` row per keyword: pages and samples read, placements per type, the advertised ASINs ranked by the share of samples they appeared in, their share of all placements and best page 1 position (share of voice), the Sponsored Brands by placements, Amazon's result count, and whether the keyword was finished. A `status` row for anything that delivered no placement: a keyword with no results (Amazon sometimes shows ads on an empty result page; those match nothing you searched for and are counted, not delivered), a page that came back with its ads hidden on every read, a page with results but no ad at all, a URL or value that could not be used, keywords not read because the run stopped. One `summary` row with every counter and the billing figures.

#### Placement types and filters

**Placement types** limits the rows to the kinds you want: you pay for those rows, plus the Search page fee on each page that delivered at least one of them. A page whose placements are all of other types is read but earns nothing, so it counts against the allowance below; a type Amazon rarely shows (`sponsored_brand_collection`) can end a run of many keywords after a few of them. The same ad shown in two kinds of placement (a grid card and a carousel, the banner and a footer brand) is two placements and two rows; shown twice in the same kind of placement on one page, it is one row.

#### Samples and share of voice

With **Samples per keyword** above 1, each keyword is read that many times in the run (each read is a separate page load on a fresh address). The keyword row then shows, for each advertised ASIN, in how many samples it appeared (`samplesSeen`, `appearanceRate`), its share of all placements of the keyword (`sharePercent`) and its best page 1 position. Each sample is billed like a separate search.

#### Caps and the charge limit

`maxPlacements` caps the run, `maxPlacementsPerKeyword` each keyword. A run also stops at the charge limit you set on it: a page is delivered only as far as its page fee and whole rows fit under the limit. Every stop is named in the summary, and keywords not read are listed in one free row.

Reads that earn nothing have an allowance: pages Amazon served with its ads hidden, blocked requests, keywords without results. A run may spend about USD 0.006 of such reads before it has charged anything, plus a share of every placement and page it has charged; the requests that end in a charged page do not count. In practice a single amazon.com keyword gets up to three reads of its first page, and a list of keywords keeps going as long as its keywords mostly have ads. A run that reaches the allowance ends with the rest of its keywords in one free `skipped` row; run them again.

### How much does it cost to scrape Amazon sponsored products?

Pay per event, no subscription. The Store pricing card shows these same prices per 1,000 events: "$20.00 / 1,000" on the Search page row means one search page costs 2 cents.

| Event | Free | Bronze | Silver | Gold | What it is |
|---|---|---|---|---|---|
| Ad placement (per 1,000) | $0.79 | $0.79 | $0.69 | $0.59 | one placement row delivered |
| Search page (per 1,000) | $20.00 | $20.00 | $18.00 | $16.00 | one result page that delivered at least one placement row |
| Advertiser name (per 1,000) | $1.00 | $1.00 | $0.90 | $0.80 | one advertiser whose EU advertiser and payer names were found, once per run (only when you ask for names) |
| Actor start | $0.029 | $0.029 | $0.029 | $0.029 | once per run |

Platinum and Diamond plans pay the Gold price. Free: pages read again because Amazon hid their ads or blocked the request, keywords without results and the ads Amazon shows on them, status rows, keyword rows and the summary.

Worked examples at the Free tier price, with the median of 25 placements per page: one keyword, one page costs 0.029 + 25 x 0.00079 + 0.02 = about $0.069. Twenty-five keywords, one page each: 0.029 + 25 x (25 x 0.00079 + 0.02) = about $1.02. Twenty-five keywords with three samples each: about $3.0.

### Input

| Field | Type | What it does |
|---|---|---|
| `keywords` | list of text | keywords, or Amazon search URLs (`https://www.amazon.com/s?k=...`, with any filters), up to 500. Also read as `searchTerms`, `search`, `queries`; URLs also under `searchUrls`, `startUrls` |
| `marketplace` | text | the store for keywords: `com`, `co.uk`, `de`, `it`, `es`, `nl`, `se`, `pl`, `com.be`, `ie`, `ca`, `com.mx`, `com.br`, `com.au`, `co.jp`, `in`, `ae`, `sa`, `sg`, `com.tr`, `eg` (default `com`); store domains and country names are read too |
| `pages` | 1 to 5 | result pages per keyword (default 1) |
| `samples` | 1 to 10 | reads of each keyword in the run (default 1) |
| `placementTypes` | list | only these placement types (default every type) |
| `advertiserNames` | true or false | EU advertiser and payer names (default false; EU stores only) |
| `maxPlacements`, `maxPlacementsPerKeyword` | whole numbers | caps (default none) |

An input with no keyword field at all runs the sample search ("protein powder" on amazon.com). An empty keyword list, a value that is not text, a number out of range or a store this Actor does not search is refused with a free row, and nothing is fetched.

#### API examples

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~amazon-sponsored-products-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["protein powder", "creatine"], "marketplace": "com", "pages": 2}'
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/amazon-sponsored-products-scraper').call({ keywords: ['proteinpulver'], marketplace: 'de', advertiserNames: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'placement').length);
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("automation_craft/amazon-sponsored-products-scraper").call(run_input={"keywords": ["yoga mat"], "samples": 3})
rows = [i for i in client.dataset(run["defaultDatasetId"]).iterate_items() if i["type"] == "keyword"]
```

### What this Actor does not do

- **amazon.fr.** Amazon's French store answers automated requests with a browser challenge that only a full browser passes; this Actor does not run one, so amazon.fr is not offered.
- **Organic results as rows.** It delivers paid placements; the organic rank of an advertised product is on its row, the organic results themselves are not delivered.
- **Display ads.** The bottom banner and the left column ad frames are filled by a script after the page loads and carry no product; they are not delivered.
- **A delivery location.** Pages are read as a visitor from the store's country sees them; no postal code or delivery address is set.
- **Mobile layouts.** The desktop result page is read; the mobile page shows a different set of placements.
- **Prime.** Amazon does not show the Prime badge to visitors who are not signed in, so there is no Prime field.
- **Ad spend, bids, impressions or clicks.** Amazon does not publish them on the search page. In the EU, the Amazon Ad Library holds impressions per ad.
- **Monitoring with memory.** Each run is a fresh reading of the keyword; it does not remember earlier runs.
- **Search volume, coupon and delivery text, product details or sales estimates.** It reads the ads of the result page; product pages are the job of the Amazon Product Scraper listed below.
- **Advertiser names outside the EU.** amazon.com, amazon.co.uk and the other non EU stores do not state who advertised.

### FAQ

#### Where can I see my competitors' ads on Amazon?

On the search result pages of the keywords you share with them: Sponsored Products cards, sponsored carousels and Sponsored Brands placements. This Actor reads those pages for your keyword list and gives one row per placement with the advertised ASIN, its position and Amazon's ad id, so you can see who bids on your keywords and where they show.

#### How do I measure share of voice on an Amazon keyword?

Read the keyword several times with **Samples per keyword** (Amazon rotates its ads between page loads). The keyword row lists each advertised ASIN with the share of samples it appeared in, its share of all placements and its best page 1 position, and the Sponsored Brands by placements.

#### How do I find out who is behind an Amazon ad?

In the EU stores Amazon states, for every ad, the advertiser and who paid for it. Switch on **EU advertiser and payer names** and both names are added to the rows (they differ often: a distributor advertising a brand's product, for example). The names are as Amazon publishes them under the EU Digital Services Act; a small seller's name can be a person's name, which is why the switch is off by default. Outside the EU Amazon shows no such statement; the ad and campaign ids and, on cards, the offer's seller id are on the rows everywhere.

#### Can I scrape Amazon search results with ads without being blocked?

The Actor reads every page from a residential address in the store's own country, through Amazon's own search call, and asks again on a fresh address when Amazon blocks a request or hides its ads. Pages that never came back with their ads are reported in a free status row and not billed.

#### Why does this Actor run with limited permissions?

It needs nothing beyond its own run: it writes to the run's dataset and to the run's own key-value store (a small ledger that keeps a restarted run from delivering a row twice). Limited permissions keep it from reading or changing anything else in your account.

### Changelog

- 0.1 (2026-10-08): first version. 21 stores, seven placement types, pages 1 to 5, samples, EU advertiser and payer names, organic rank on ad rows, free rows for keywords without results and pages served without ads.

### More data tools by Automation Craft

- [Amazon Product Scraper - Search, Best Sellers](https://apify.com/automation_craft/amazon-data-scraper)
- [Meta Ad Library Scraper - All Placements, Filters](https://apify.com/automation_craft/meta-ads-library-scraper)
- [Google Ads Transparency Scraper - Decoded Creatives](https://apify.com/automation_craft/google-ads-transparency-scraper)
- [Microsoft Ads Library Scraper - Competitor Ads](https://apify.com/automation_craft/microsoft-ads-library-scraper)
- [TikTok Ads Library Scraper: EU Ads, No Login](https://apify.com/automation_craft/tiktok-ads-library-scraper)
- [LinkedIn Ad Library Scraper: Ads by Company](https://apify.com/automation_craft/linkedin-ad-library-scraper)
- [Pinterest Ads Library Scraper - EU Ads Repository](https://apify.com/automation_craft/pinterest-ads-library-scraper)

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/amazon-sponsored-products-scraper/changelog.md

# Actor input Schema

## `keywords` (type: `array`):

The searches to read, one per line: a keyword (searched on the store chosen below) or a full Amazon search URL such as https://www.amazon.de/s?k=proteinpulver (its own store and filters are kept). Up to 500 per run. Each keyword is one search on Amazon's own result page.

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

The store keywords are searched on (pasted URLs keep their own store). The Actor reads each store from a residential address in that store's country, because Amazon hides ads from datacenter addresses. amazon.fr is not offered (see the README).

## `pages` (type: `integer`):

How many result pages of each keyword to read, from 1 to 5. Page 1 holds most ads (about 25 placements); later pages hold more Sponsored Products cards. Default 1.

## `samples` (type: `integer`):

How many times to read each keyword in this run, from 1 to 10. Amazon rotates its ads between page loads, so several samples show which products appear most often (share of voice, in the keyword row). Each sample is billed like a separate search. Default 1.

## `placementTypes` (type: `array`):

Deliver only these kinds of placement (and pay only for them). Leave empty for every kind.

## `advertiserNames` (type: `boolean`):

In the EU stores (amazon.de, .it, .es, .nl, .se, .pl, .com.be, .ie) Amazon states, for each ad, who advertised and who paid. When this is on, the Actor asks for them once per advertiser and adds both names to the rows; each advertiser found is charged once per run as an Advertiser name event. Other stores have no such statement.

## `maxPlacements` (type: `integer`):

Stop after this many placement rows in the whole run. Leave empty for no cap.

## `maxPlacementsPerKeyword` (type: `integer`):

Stop reading a keyword after this many placement rows (across its pages and samples). Leave empty for no cap.

## Actor input object example

```json
{
  "keywords": [
    "protein powder"
  ],
  "marketplace": "com",
  "pages": 1,
  "samples": 1
}
```

# Actor output Schema

## `items` (type: `string`):

No description

# 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 = {
    "keywords": [
        "protein powder"
    ],
    "marketplace": "com",
    "pages": 1,
    "samples": 1,
    "advertiserNames": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/amazon-sponsored-products-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 = {
    "keywords": ["protein powder"],
    "marketplace": "com",
    "pages": 1,
    "samples": 1,
    "advertiserNames": False,
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "protein powder"
  ],
  "marketplace": "com",
  "pages": 1,
  "samples": 1,
  "advertiserNames": false
}' |
apify call automation_craft/amazon-sponsored-products-scraper --silent --output-dataset

```

## MCP server setup

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

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/DCVZ3hJ6ghLqr5R1D/builds/DYk6dCLKOVGhdR2tg/openapi.json
