By the end of this tutorial, you will have a short Python script that turns an Amazon search into structured JSON: one row per product with its ASIN, title, current price, strikethrough list price, discount percentage, star rating, review count, a Prime flag, a sponsored flag and a clean /dp/ link.
We use the Apify Actor Amazon Product & Price Scraper (reventadata/amazon-scraper). It is for developers who track prices, compare products by rating, or watch what Amazon shows for a keyword, and would rather read rows than result cards. It covers 9 Amazon marketplaces: the US, UK, Germany, Spain, France, Italy, Canada, Japan and India.
You will learn how to configure a search, run it from Python, read every field, and filter the results before they reach your dataset.
⏱️ Time: about 10 minutes for the setup.
Prerequisites
You need three things:
- An Apify account. You can sign up for free.
- Python 3.11 or newer, which
apify-clientrequires. - Your API token, from the Integrations settings page in Apify Console.
Install the client:
pip install "apify-client~=3.0" Then keep the token in an environment variable, never in the script:
export APIFY_API_TOKEN="<your token>" No scraping code is required: the Actor handles fetching and parsing.
What you'll achieve
You will get a dataset with one row per search result, for the keywords and marketplace you choose. Each row holds the fields printed on Amazon's result card: price in the marketplace's currency, list price when Amazon shows one crossed out, the discount computed from those two, rating, review count, Prime and sponsored flags, and the product image.
Example use case: you follow business laptops on amazon.com. You search thinkpad, keep rows rated 4 stars or more, drop sponsored placements, and compare prices against list prices. That is the configuration this tutorial builds up.
The sample rows below come from a capture of amazon.com page 1 for "thinkpad", dated 2026-10-22, read with the Actor's own parser. They are not from a run started for this post.
Step 1: Access Amazon Product & Price Scraper
Go to the Amazon Product & Price Scraper page on Apify Store. If you prefer clicking to coding, Apify Console has the same fields in the Actor's Input tab, and you press Start there.
In this tutorial we drive it from Python, so the same search is easy to repeat.
Step 2: Configure the search
The main input is searchQueries: a list of keywords, each searched on its own. Pick the marketplace with country, one of US, UK, DE, ES, FR, IT, CA, JP or IN. Prices come back in that marketplace's currency: USD, GBP, EUR, CAD, JPY or INR.
maxItems caps the saved rows across all your queries (20 by default). The Actor reads at most 7 result pages per query and stops earlier when a page is empty or has no next-page link.
Here is the script. Its input is the Actor's own starting example:
import os from apify_client import ApifyClient client = ApifyClient(os.environ["APIFY_API_TOKEN"]) run_input = { "searchQueries": ["thinkpad"], "country": "US", "maxItems": 20, "sortBy": "relevance", } run = client.actor("reventadata/amazon-scraper").call(run_input=run_input) if run is None or run.status != "SUCCEEDED": raise SystemExit(f"Run did not succeed (status: {run.status if run else 'unknown'})") for item in client.dataset(run.default_dataset_id).iterate_items(): print(item["asin"], "|", item["price"], item["currency"], "|", item["rating"], "|", item["title"][:60]) 💡 Tip: keywords work like Amazon's search box, but the Actor adds one check of its own: every word of your query must appear in the product title (case and accents ignored). On the captured "thinkpad" page, 20 of the 22 results passed. The two that did not were a "Lenovo 15.6 FHD Essential Laptop" and a sponsored MacBook.
Step 3: Add sort order and filters
sortBy goes to Amazon in the search URL: relevance, price_low_to_high, price_high_to_low, review_rank or newest. Because country and sortBy are fixed lists in the input schema, a misspelled value is refused before the run starts.
The other filters run inside the Actor, after each page is read:
-
minPrice/maxPrice: a price band in the marketplace currency. When either is set, rows without a price are dropped. -
minRating: a whole number from 1 to 5. Unrated products are dropped when it is set. -
primeOnly: keeps rows whereisPrimeis true (see the next section for what that flag means). -
excludeSponsored: drops results Amazon labels as sponsored.
On the captured page, the 20 rows that passed the keyword check included 5 sponsored ones and 2 without a rating. So excludeSponsored: true would keep 15 of them, and minRating: 4 would keep 18.
Note: filtered rows are never saved, and
maxItemscounts only saved rows.
Step 4: Run the Actor
Save the script as amazon_search.py and run it with python amazon_search.py. .call() starts the run on Apify and waits for it to finish; the script then checks the status and prints each row.
Behind the scenes, the Actor builds Amazon's search URL for your keyword, marketplace, page and sort order, reads the result cards, applies your filters, and saves the rows that pass. It pauses one second between pages. A product that shows up under two of your keywords is saved once, matched by ASIN.
For marketplaces outside the US and Canada, the Actor fetches pages through a web-unlocking service first. In our recon on 2026-10-17, amazon.de and amazon.es answered requests from US datacenter IPs with a captcha page.
⚠️ Tip: in Console, the run's tabs include its log, which is where to look first if something goes wrong.
Step 5: View and download results
Each row prints in your terminal. In Console, the rows sit in the run's Output tab, and Export downloads them. Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.
Here is a real row from the 2026-10-22 amazon.com capture, the third result on the page. I left out scrapedAt, the time the page was read:
{ "asin": "B0HB8D3NQ3", "title": "Lenovo ThinkPad E16 Gen 3, 16GB DDR5 RAM, 512GB SSD, 500GB External HDD", "price": 1139.98, "currency": "USD", "listPrice": 1749.99, "discountPercentage": 35, "rating": 4.6, "reviewsCount": 343, "url": "https://www.amazon.com/dp/B0HB8D3NQ3", "image": "https://m.media-amazon.com/images/I/71GqQ5PQ+hL._AC_UY218_.jpg", "isPrime": true, "isSponsored": false, "country": "US" } And a trimmed row from an amazon.in capture of the same date (page 2 for "pressure cooker"):
{ "asin": "B0843YY4QP", "price": 3292.0, "currency": "INR", "listPrice": 4140.0, "discountPercentage": 20, "rating": 4.3, "reviewsCount": 1687, "isPrime": false, "country": "IN" } Understanding your results
Every row has the same 14 fields:
-
asin: Amazon's 10-character product id, used to save each product once. -
title: the product name, with the brand joined on when the card prints it separately ("Lenovo ThinkPad T16, ...", not "Lenovo"). -
price,currency: the current price as a number, in the marketplace currency. -
listPrice: the crossed-out price, ornullwhen the card shows none. On the captured page, 11 of 22 results had one. Check it is abovepricebefore you use it: on the amazon.in capture, 5 of 48 rows carried a per-unit price (such as "/100 ml") here instead, and theirdiscountPercentageisnull. -
discountPercentage: computed by the Actor frompriceandlistPrice, rounded;nullunless the list price is higher. The captured page ran from 14 to 48 percent. -
rating: stars out of 5, ornull. Two captured rows had none. -
reviewsCount: the exact count from Amazon's "N ratings" label; the India card above shows "(1.6K)", the row 1,687. -
url: a cleanhttps://www.<domain>/dp/<ASIN>link. -
image: the thumbnail URL. -
isPrime,isSponsored: flags read from the card. -
country: the marketplace code. -
scrapedAt: an ISO 8601 UTC timestamp.
Pro tips and advanced usage
- Read
isPrimeas "labelled Prime on this visit". Logged-out pages no longer show a Prime badge; the Actor setsisPrimewhen the card shows Amazon's "Join Prime to get FREE delivery" line. On the captured amazon.com page, 8 of 22 results had it. The Actor's schema notes that amazon.in showed no Prime line on 2026-10-22, so India rows arefalse. - Check ratings next to review counts. Two captured ThinkPads had 5.0 stars, from 2 and 3 reviews. Sort on both columns, not one.
- Batch keywords in one run. Put several phrases in
searchQueries; rows are de-duplicated by ASIN across them, andmaxItemscaps the total. - Use Amazon's sort for depth. With at most 7 pages per query,
price_low_to_highorreview_rankchanges which products you reach. - Skip the polling. Attach a webhook for the
ACTOR.RUN.SUCCEEDEDevent. Its payload'sresourceis "the response of the Get Actor run API endpoint" (Apify docs), which carriesdefaultDatasetId.
Troubleshooting common issues
- A run saved 0 rows (status message "0 results for ..."). A run that is blocked, cannot read a result page or finds a page without product cards ends FAILED. If the pages loaded with product cards but the filters rejected them all, it ends SUCCEEDED with an empty dataset. The log's summary line lists rejections by reason (
keyword_mismatch,price_bounds,rating_threshold,prime_required,sponsored_excluded,duplicate), so you can see which filter removed everything. -
primeOnlyreturns nothing. Likely on amazon.in, where no Prime line was seen; turn it off there. - Fewer rows than
maxItems. The search ran out of pages (7 at most), or your filters dropped the rest. Each page logs how many cards it parsed and kept. - The run is refused at the start. A
countryorsortByvalue outside the schema's list never starts a run; the caller gets an error instead. - Questions? Use the Actor's Store page.
Next steps
For current pricing and details, see the Store page.
To repeat a search, save your input as a task and add a schedule; Apify schedules use cron expressions. To push rows into other tools, Apify integrates with n8n, Make and Zapier.
What are you planning to track on Amazon? Drop a comment! 💬
