Amazon Today's Deals Scraper
Pricing
Pay per usage
Amazon Today's Deals Scraper
Amazon Today’s Deals Scraper helps you extract structured deal data from Amazon. Retrieve product info, discount percentages, pricing history signals, and availability efficiently. Designed for ecommerce teams and data pipelines.
Pricing
Pay per usage
Rating
5.0
(1)
Developer
API Empire
Maintained by CommunityActor stats
0
Bookmarked
11
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
Amazon Deals Scraper — Today's Deals, Prices and Ratings JSON
The Amazon Today's Deals Scraper extracts Amazon's live Today's Deals feed from the US storefront and returns every discounted product as a flat JSON row: deals and deal windows, products, prices and savings, star ratings with the full review histogram, and category and brand taxonomy. Every row is typed, normalized JSON with stable key names — no HTML, no selectors, no parsing step. By the end of this page you will know which 27 keys land in your dataset, the real per-run ceiling, and how to call it from Python.
What is the Amazon Today's Deals Scraper?
The Amazon Today's Deals Scraper is an Apify Actor that reads the same promotions feed that powers amazon.com/deals (the page long known as Goldbox) and converts each promotion into one structured record. It targets the US marketplace only — the promotions endpoint is pinned to Amazon's US marketplace ID ATVPDKIKX0DER in src/main.py, and the currency-preference header is pinned to USD.
No Amazon account, login, cookie or API key is required. The Actor fetches the public deals page, harvests the CSRF token that Amazon serves inline in that HTML, and calls the promotions API with it. There is no credential input in the schema, and there is nothing to authorize on Amazon's side. The only account you need is an Apify account, because the Actor runs on the Apify platform — from the Apify Console or through the Apify API.
What it returns in a single pass:
- Deals —
dealId,dealType,dealState,dealStartTime,dealEndTime, plus Amazon's own badge text indealBadgeLabelanddealBadgeMessage. - Products —
asin,title,link,image. - Prices and savings —
priceToPay,basisPrice,savingsAmount,savingsPercentageValue,currency. - Ratings and reviews —
rating,reviewCountand the complete five-bucket histogram (starsFivePercentdown tostarsOnePercent). - Category and brand taxonomy —
category,productType,glProductGroup,brandId. - Export as JSON, JSONL, CSV, Excel, XML or HTML from the Apify dataset, or read the dataset straight from the Apify API.
- No proxy management, no browser, no parsing. The Actor takes no proxy input and launches no headless browser.
📦 What data does the Amazon Today's Deals Scraper collect?
Each pushed record carries five distinct data groups on one flat row — deal metadata, product identity, pricing, review aggregates and catalog taxonomy — so you never have to join two datasets to answer "which brand discounted what, by how much, and how well is it rated?"
| Data Type | Key Fields | JSON Field Names |
|---|---|---|
| Deals and deal windows | Deal ID, deal type, live state, start and end timestamps | dealId, dealType, dealState, dealStartTime, dealEndTime |
| Deal badges | Amazon's own badge label and messaging text, as rendered on the tile | dealBadgeLabel, dealBadgeMessage |
| Products | ASIN, product title, canonical product URL, primary image URL | asin, title, link, image |
| Prices and savings | Deal price, list price the discount is measured from, money saved, discount percentage, currency stamped from the payload | priceToPay, basisPrice, savingsAmount, savingsPercentageValue, currency |
| Ratings and reviews | Average star rating, review count, and the percentage of reviews in each star bucket | rating, reviewCount, starsFivePercent, starsFourPercent, starsThreePercent, starsTwoPercent, starsOnePercent |
| Category and brand | Website display group, finer product type, machine-readable product group symbol, Amazon brand identifier | category, productType, glProductGroup, brandId |
All of these arrive on the same HTTP request. The Actor sends one large expand= accept header (ACCEPT_EXPAND in src/main.py) that asks the promotions API for title, links, images, customer-review summary, product category, brand logo, price, deal details and deal badge in a single response, so a richer row costs no extra requests and no extra time.
Need more Amazon data?
Today's Deals is a discovery feed, not a catalog. If you need the full product page behind an ASIN — variations, bullet points, seller, full description — pair this Actor with Amazon Product Scraper and feed it the asin values this Actor returns. For rank-ordered category leaders rather than time-boxed promotions, Amazon Bestsellers Scraper covers the Best Sellers charts, and Amazon Search Products Scraper covers keyword result pages. Amazon ASIN Scraper is the usual companion when you already hold an ASIN list and want to enrich it.
How does the Amazon Today's Deals Scraper work under the hood?
Amazon's Today's Deals page is a React front end that calls a JSON promotions endpoint; this Actor calls that endpoint directly instead of rendering the page. The flow, in the order src/main.py executes it:
- Fetch the deals page. A single
GET https://www.amazon.com/dealswith a desktop Chrome user-agent. The response is validated on two axes: HTTP status must be200and the HTML must be at leastBLOCK_SIZE_FLOOR= 20,000 bytes. A real deals page is well over 100 KB; a few kilobytes means a block shell was served. If either check fails, the run raisesRuntimeError("Deals page looks blocked: HTTP <status>, <size> B"). - Harvest the CSRF token. Three regular expressions are tried in order against that HTML (
csrfToken":"…", acsrf-tokenkey form, and a<meta name="csrf-token">form). The first match wins and is logged asDeals page OK (HTTP 200, … B); CSRF token harvested.If none match, the run raisesRuntimeError("No CSRF token found in the deals page"). - Call the promotions API.
GET https://data.amazon.com/api/marketplaces/ATVPDKIKX0DER/promotionswith the harvested token in thex-api-csrf-tokenheader,x-cc-currency-of-preference: USD, and the longexpand=accept header described above. The expansion deliberately scopesprice,dealDetailsanddealBadgetobuyingOptions[]— at product scope this API answers HTTP 200 and silently returns nothing. - Paginate with
startIndex. The first request sends no page parameter. Each response carriesentity.nextIndex, which becomes the nextstartIndex. Pagination stops whennextIndexis missing, when it repeats the previous value, when 500 unique ASINs have been seen, or when the requestedlimithas been pushed. - Build and push rows.
iter_rows()insrc/extract_deals.pywalksentity.rankedPromotions, deduplicates byasin, and builds one flat row per promotion. Real deals are pushed to the dataset with therow_resultcharged event; filler rows are dropped.
Two defensive rules are worth knowing because they shape the data you get:
- Never trust key presence. This API answers HTTP 200 with a node whose
typeiserror/v1instead of rejecting an expansion it cannot serve. The_ent()guard insrc/extract_deals.pyreturns an empty dict unless the node'stypematches exactly the expected type (product.price/v1,product.deal-details/v1,product.deal-badge/v1,product.customer-reviews-summary/v1,product.offer.product-category/v1,product.brand-logo/v1). A naive "is the key there?" check would report full coverage on an entity that returned nothing. nullover fake. A field Amazon did not send is emitted asnull— never0,0.0or"".ratingand the star percentages are only written if they are numeric;reviewCountonly if it is an integer. This means you can safely treatnullas "unknown" and0as "genuinely zero" in downstream analytics.
Retries. Each promotions request is attempted up to MAX_RETRIES = 3 times with a 45-second total timeout per attempt and a 0.6 s / 1.2 s backoff between attempts. A response only counts as success at HTTP 200 with a body of at least 20,000 bytes. After three failed attempts the Actor logs Page fetch failed (…) and stops paginating, keeping every row already pushed — the run does not throw away collected data because a later page failed.
How does this differ from the official Amazon Product Advertising API?
Amazon's Product Advertising API (PA-API 5.0) is an affiliate-facing API for looking up items you already know about — GetItems by ASIN, SearchItems by keyword, GetBrowseNodes for category trees. It has no "today's deals" operation. This Actor does the opposite: it reads the promotions feed itself and hands you the set of ASINs that are discounted right now, with the deal window attached.
| Feature | Amazon Product Advertising API 5.0 | Amazon Today's Deals Scraper |
|---|---|---|
| Access requirement | Amazon Associates account, approved, with an active partner tag and signed requests (access key, secret key) — see Amazon's PA-API 5.0 onboarding documentation at webservices.amazon.com/paapi5/documentation | Apify account only; no Amazon credentials, no login, no cookie |
| Keeping access | Amazon's PA-API documentation ties continued access and usage limits to qualifying sales generated through your associate tag | Nothing to maintain on Amazon's side; the feed is public |
| Deals discovery | No Today's Deals / promotions listing operation in the published operation list (GetItems, GetVariations, SearchItems, GetBrowseNodes) | Reads the promotions feed directly and returns whatever is discounted at run time |
| Deal window fields | Offer data is item-centric | dealId, dealType, dealState, dealStartTime, dealEndTime per promotion |
| Review data | Review content is not returned by PA-API 5.0 | Aggregate rating, reviewCount and the full five-bucket star histogram |
| Output shape | Resource-selection model — you request resources per call and the response shape varies with what you asked for | Fixed 27-key flat row on every record, same keys every run |
| Setup time | Associates application, key management, request signing | Set limit, press Start |
Use PA-API when you are a registered Amazon Associate building affiliate links and need Amazon-sanctioned item data tied to your partner tag. Use this Actor when the deal list itself is the thing you need — the ASINs on promotion today, at what discount, ending when — and you do not want to run an affiliate program to get it.
Why do developers and teams scrape Amazon deals?
Discount data is time-boxed, which makes it uniquely valuable and uniquely perishable. Four audiences use this Actor for very different reasons.
For AI engineers and agent builders
A shopping agent needs a grounded, current answer to "what is discounted right now, and is it actually a good deal?" One run gives an LLM everything needed for that judgement without a scraping tool call per product: priceToPay against basisPrice gives the real discount, savingsPercentageValue gives Amazon's own math, rating plus reviewCount plus the star histogram let the model discount a 4.8 rating built on 12 reviews, and dealEndTime tells it what is expiring. Index rows into a vector store keyed by asin, or expose the Actor as a tool that the agent calls with a limit and reasons over the returned JSON — no HTML parsing inside the agent loop.
For affiliate publishers and deal media
Deal blogs, newsletters and Telegram or WhatsApp deal channels live or die on freshness. Schedule the Actor to run each morning, filter on savingsPercentageValue and category, and you have a publish-ready shortlist with title, image, link and the badge text Amazon itself is showing (dealBadgeLabel, dealBadgeMessage) — so your copy matches the offer the reader will see when they click. dealEndTime powers "ends tonight" countdowns, and dealState tells you when a promotion is no longer live so you can pull a dead post before readers hit it.
For pricing analysts and retail researchers
Promotion depth is a competitive signal. Snapshot the feed on a schedule and diff run-over-run on asin plus dealId to build a discount history: which glProductGroup and category values Amazon is pushing hardest, how deep savingsPercentageValue goes by season, and how long a typical promotion runs (dealStartTime to dealEndTime). Because basisPrice and priceToPay are returned side by side and null is never substituted with 0, aggregate statistics stay honest — a missing list price does not silently become a 100% discount.
For developers building data products
Everything the Actor returns is a stable, flat key — nothing nested, nothing conditional — so a dataset row maps one-to-one onto a database column set with no transformation layer. Point a scheduled run at a webhook, stream new rows into Postgres or BigQuery keyed on asin, and build price-drop alerts, browser extensions, comparison widgets or Slack notifications on top. Because the Actor pushes rows incrementally as it paginates, a partially completed run still leaves usable data in the dataset rather than nothing.
🚀 How to scrape Amazon Today's Deals (step by step)
The Actor runs on the Apify platform. There are exactly two ways to start it — the Apify Console UI, or the Apify API with your Apify token. There is no separate signup and no Amazon API key to paste into the input.
- Open the Actor on its Apify Store listing and click Try for free, or open it from your Apify Console if you have already added it.
- Set
limit— the only input parameter. It is optional; leaving it empty uses the schema default of10. Start small while you inspect the shape of the output. - Raise
limitfor a full sweep. There is no URL, category or keyword filter to configure — the Actor always reads the whole US Today's Deals feed in feed order and stops when it has pushedlimitdeals. Filter bycategory,savingsPercentageValueordealTypeafter the run, in your dataset query. - Click Start. Watch the log: it prints the collection target, then
Amazon reports totalCount=…, then a final line readingScanned N promotions | dropped M non-deal filler rows | pushed P. - Download the results from the Storage → Dataset tab as JSON, JSONL, CSV, Excel, XML or HTML, or pull them programmatically from the Apify dataset API.
To run it repeatedly, use Apify Schedules (for example, once each morning) and an Apify webhook on run success to push the new dataset into your own system.
What to do when Amazon changes its structure
Amazon rotates the deals front end regularly. This Actor is maintained against the promotions endpoint and its CSRF handshake, and the output contract is deliberately stable: the same 27 keys, the same types, null for anything Amazon omits. When the upstream payload shifts, the fix happens inside the extraction layer — your column names and downstream integrations do not change.
⬇️ Input
The Actor takes a single optional setting. There is no start URL, no cookie field, no session token, no proxy configuration and no marketplace selector — the input schema in .actor/actor.json declares exactly one property and an empty required array.
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
limit | No | integer | Number of deals to scrape. Default 10, schema minimum 1, schema maximum 10000. How many deals to collect. Amazon's Today's Deals feed exposes a fixed window of 500 promotions per run, so any higher value is coerced to 500 and the coercion is written to the log. Non-deal filler rows are dropped and never counted toward this number. | 100 |
Example JSON input
Every parameter the schema defines, shown with a realistic value:
{"limit": 100}
Running with an empty input object is valid and collects 10 deals:
{}
How limit is actually applied
read_limit() in src/main.py is short and worth knowing verbatim, because three things happen there that the schema alone does not tell you:
- Values above 500 are coerced down to 500.
HARD_WINDOWis 500. The coercion is logged as a warning naming both the requested and the effective value, so a run that asked for 5,000 is not silently truncated without a trace. The schema'smaximumof10000exists for input compatibility — it is not an achievable result count. - Values below 1 are raised to 1 by
max(1, …). The schema'sminimumof1already blocks this from the Console, but an API caller sending0or-5gets 1 deal rather than an error. - A non-numeric
limitsilently falls back to10. Ifint(inp.get("limit", 10))raisesTypeErrororValueError— for example if an API caller sends"limit": "one hundred"or"limit": null— the Actor swallows the exception and uses the schema default of 10 without writing a log line. If a run returns 10 rows when you asked for 400, check that your caller sent a JSON number and not a string.
Common pitfall: setting limit to a number in the thousands and expecting thousands of rows. This feed is a fixed 500-promotion window; the highest useful value is 500, and even then the pushed count can land slightly under it because filler rows consume slots in the 500-ASIN window. See "How many results can you scrape" below.
⬆️ Output
Every run pushes one flat, typed JSON object per deal to the Apify dataset. The key set is fixed at 27 keys and is identical on every record — the same keys the default dataset view displays, in the same names. There are no nested objects, no arrays, and no conditional keys: a field Amazon did not return arrives as null, never as 0, 0.0 or an empty string. Export from the dataset as JSON, JSONL, CSV, Excel, XML or HTML, or read it directly from the Apify API.
The internal flag _isRealDeal used to separate deals from filler is removed from the row before it is pushed, so it never appears in your dataset.
Scraped deal
A complete record, with every key the Actor writes:
{"asin": "B0D1XD1ZV3","title": "Wireless Earbuds Bluetooth 5.4 Headphones, 48H Playtime, IPX7 Waterproof","link": "https://www.amazon.com/Wireless-Earbuds-Bluetooth-Headphones/dp/B0D1XD1ZV3","image": "https://m.media-amazon.com/images/I/71abcDEfGhL.jpg","priceToPay": 25.49,"basisPrice": 39.99,"savingsAmount": 14.5,"savingsPercentageValue": 36,"currency": "USD","dealId": "8e46b66b","dealType": "BEST_DEAL","dealState": "AVAILABLE","dealStartTime": "2026-07-20T07:00:00Z","dealEndTime": "2026-08-01T06:59:59.999Z","dealBadgeLabel": "36% off","dealBadgeMessage": "Limited time deal","rating": 4.4,"reviewCount": 8480,"starsOnePercent": 5,"starsTwoPercent": 4,"starsThreePercent": 7,"starsFourPercent": 12,"starsFivePercent": 72,"category": "Consumer Electronics","productType": "HEADPHONES","glProductGroup": "gl_wireless","brandId": "5209892"}
Scraped deal with partial coverage
Not every discounted product carries a review summary, a brand logo or a category node. Those rows still ship — with null in the missing places, which is what makes them safe to aggregate:
{"asin": "B0CJ7MQXK9","title": "Stainless Steel Insulated Water Bottle, 32 oz","link": "https://www.amazon.com/Stainless-Insulated-Water-Bottle-32oz/dp/B0CJ7MQXK9","image": "https://m.media-amazon.com/images/I/61ZzQwErTyL.jpg","priceToPay": 18.99,"basisPrice": 24.99,"savingsAmount": 6.0,"savingsPercentageValue": 24,"currency": "USD","dealId": "c1f0a7d2","dealType": "BEST_DEAL","dealState": "AVAILABLE","dealStartTime": "2026-07-24T07:00:00Z","dealEndTime": "2026-07-28T06:59:59.999Z","dealBadgeLabel": "24% off","dealBadgeMessage": null,"rating": null,"reviewCount": null,"starsOnePercent": null,"starsTwoPercent": null,"starsThreePercent": null,"starsFourPercent": null,"starsFivePercent": null,"category": "Kitchen","productType": "DRINKING_VESSEL","glProductGroup": "gl_kitchen","brandId": null}
Output field reference
Product identity
| Field | Type | Description |
|---|---|---|
asin | string | Amazon Standard Identification Number. Empty string if the promotion carried no ASIN; rows without an ASIN are never yielded, so in practice this is always populated and is the dedup key. |
title | string | null | Product display title, taken from the product.offer.title/v1 expansion. |
link | string | null | Absolute product URL, built as https://www.amazon.com + the viewOnAmazon path from the links expansion. null when Amazon returned no view link. |
image | string | null | Primary product image URL, assembled as https://m.media-amazon.com/images/I/<physicalId>.<extension>. The high-resolution variant is used when present, with the low-resolution variant as fallback; jpg is used when no extension is given. |
Pricing and savings
| Field | Type | Description |
|---|---|---|
priceToPay | number | null | Current deal price, coerced to float. A row without a priceToPay is treated as filler and is never pushed, so this key is populated on every exported record. |
basisPrice | number | null | The list price the discount is measured against. |
savingsAmount | number | null | Money saved, from Amazon's savings.money node. |
savingsPercentageValue | number | null | Discount percentage, taken verbatim from Amazon's savings.percentage.value — Amazon's own arithmetic, not recomputed here. |
currency | string | null | ISO currency code stamped from the payload itself (priceToPay currency, falling back to basisPrice currency), not assumed from the marketplace. In practice USD, because the request pins x-cc-currency-of-preference: USD. |
Deal metadata
| Field | Type | Description |
|---|---|---|
dealId | string | null | Amazon's promotion identifier. Combined with asin, this is the stable key for run-over-run diffing. |
dealType | string | null | Promotion type as Amazon classifies it, e.g. BEST_DEAL. |
dealState | string | null | Promotion state, e.g. AVAILABLE. |
dealStartTime | string | null | ISO-8601 timestamp when the promotion began. |
dealEndTime | string | null | ISO-8601 timestamp when the promotion ends — the field to sort on for "ending soon" logic. |
dealBadgeLabel | string | null | First text fragment of the badge label Amazon renders on the tile, e.g. "36% off". null when the badge expansion returned an error node or carried no fragments. |
dealBadgeMessage | string | null | First text fragment of the badge messaging, e.g. "Limited time deal". |
Ratings and reviews
| Field | Type | Description |
|---|---|---|
rating | number | null | Average star rating. Written only when Amazon returned a numeric value; otherwise null. |
reviewCount | integer | null | Total customer reviews. Written only when Amazon returned an integer; otherwise null. |
starsFivePercent | number | null | Percentage of reviews at five stars. |
starsFourPercent | number | null | Percentage of reviews at four stars. |
starsThreePercent | number | null | Percentage of reviews at three stars. |
starsTwoPercent | number | null | Percentage of reviews at two stars. |
starsOnePercent | number | null | Percentage of reviews at one star. |
Category and brand
| Field | Type | Description |
|---|---|---|
category | string | null | Human-readable website display group, e.g. "Consumer Electronics". |
productType | string | null | Finer-grained Amazon product type, e.g. "HEADPHONES". |
glProductGroup | string | null | Machine-readable product-group symbol, e.g. "gl_wireless" — the most reliable field for bucketing at scale. |
brandId | string | null | Amazon's numeric brand identifier, parsed out of the brand-logo URL with the pattern /brands/(\d+)/logo. null when the product has no brand logo. |
💰 What gets charged, and what does not
This Actor is billed per result through the pay-per-event model. It emits exactly one charged event name, row_result, and it emits it in exactly one place — the Actor.push_data(row, charged_event_name="row_result") call in src/main.py. That means:
- You are charged once per exported deal row. One
row_resultevent, one dataset record, one deal. - Filler rows are never charged. Amazon's deals carousel mixes in promotional tiles that carry a title and an ASIN but no deal details and no price. The Actor flags those with an internal
_isRealDealcheck (bool(dealDetails) and priceToPay is not None), increments a dropped counter, andcontinues — the row is never pushed, so no event fires. - Failed page fetches are never charged. When a promotions request fails all three attempts,
fetch_page()returnsNone, the pagination loop breaks, and no row is produced. Nothing is charged for the failed HTTP work. - A blocked or empty run costs no result events. If the deals page is blocked or no CSRF token is found, the Actor raises before any push. If Amazon returns no usable promotions, the log says
No deals were collected - Amazon returned no usable promotions.and the dataset is empty. - There are no error rows or accounting rows in the dataset. Some Actors push status records alongside results and you have to filter them out; this one does not. Every record in the dataset is a real deal, so no filter expression is needed —
dataset.itemsis your result set as-is.
Platform compute usage is billed by Apify separately from result events, exactly as it is for any Actor run.
How does this Actor compare to other Amazon deals scrapers?
Several Today's Deals Actors exist on the Apify Store. The rows below are observable properties, checkable in a single run.
| Feature | Amazon Today's Deals Scraper (this Actor) | Typical alternative |
|---|---|---|
| Fields per row | 27 fixed keys on every record, including the full star histogram and brand/category taxonomy | Deal and price basics. The sample output block in piotrv1001/amazon-todays-deals-scraper's listing README shows 12 keys — asin, basisPrice, priceToPay, currency, savingsAmount, savingsPercentageValue, title, link, dealStartTime, dealEndTime, dealState, image — checked on the Apify Store 2026-07-25; not measured here |
| Ratings and review histogram | rating, reviewCount and five star-bucket percentages on the same request as the price | Not present in that listing's documented sample output (checked 2026-07-25) |
| Marketplace coverage | US storefront only, pinned to marketplace ATVPDKIKX0DER, prices in USD | The same listing advertises a domain input covering 13 Amazon regional sites (checked on the Apify Store 2026-07-25 — not measured here). If you need non-US deals, that breadth is a genuine difference in its favour |
| Missing-value policy | null for anything Amazon omitted; never a substituted 0 or "", so aggregates stay honest | Varies by Actor; substituted zeros are common and silently distort averages |
| Non-deal filler handling | Detected via deal-details + price check, dropped before push, counted in the log, and never charged | Generally undocumented |
| Documented per-run ceiling | Stated explicitly: 500-promotion feed window, with over-requests coerced and logged | Input tables commonly advertise ranges up to 10,000 without stating the feed's real window |
If you are building an AI agent or a RAG pipeline, the output-format row is the decision-maker: parsing HTML inside an agent loop is a reliability failure mode, not a feature. If you are building a multi-country deal aggregator, marketplace coverage is the decision-maker, and this Actor is US-only by design.
How many results can you scrape with the Amazon Today's Deals Scraper?
The hard ceiling is 500 deals per run, and it comes from Amazon, not from the Actor. HARD_WINDOW is 500 in src/main.py because Amazon's promotions feed reports entity.totalCount as 500 regardless of how deep you page. Any limit above 500 is coerced down and the coercion is logged.
Pagination works through a single parameter, startIndex — the only page parameter this API accepts. The first request omits it; every subsequent request uses the entity.nextIndex value from the previous response. The loop stops on the first of these conditions:
- the requested
limithas been pushed; nextIndexis absent, or repeats the previous index (Amazon's end-of-feed signal);- 500 unique ASINs have been seen;
- a page failed all three fetch attempts.
Two things can make a run return slightly fewer rows than limit even at limit: 500. First, rows are deduplicated by asin, so an ASIN promoted twice in the feed is exported once. Second, the 500-ASIN stop condition counts every unique ASIN scanned — including filler rows that were dropped — so filler consumes slots inside the window. The final log line always tells you exactly what happened: Scanned N promotions | dropped M non-deal filler rows | pushed P.
For more than 500 deals across a day, schedule several runs. The feed rotates as promotions start and end, so runs spaced through the day return overlapping but not identical sets; deduplicate on asin plus dealId when you merge them.
Integrate the Amazon Today's Deals Scraper and automate your workflow
The Actor runs on Apify, so it works with any language or tool that can send an HTTP request to the Apify API — or with any platform that already has an Apify connector.
REST API integration
Start a run and read the dataset with the official Apify Python client. Authentication is your Apify API token; there is no Amazon credential anywhere in this flow.
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("<YOUR_USERNAME>/amazon-todays-deals-scraper").call(run_input={"limit": 100})for deal in client.dataset(run["defaultDatasetId"]).iterate_items():if deal["savingsPercentageValue"] and deal["savingsPercentageValue"] >= 30:print(deal["asin"], deal["title"][:60], deal["priceToPay"],f'-{deal["savingsPercentageValue"]}%', deal["dealEndTime"])
Works in Python, Node.js, Go, Ruby and cURL — the same run and dataset endpoints back every Apify client library, and GET /v2/datasets/{datasetId}/items returns the rows as plain JSON.
Automation platforms (n8n, Make, LangChain)
n8n ships an Apify node: add it to a workflow, choose the Run an Actor operation, select this Actor, pass {"limit": 200} as the run input, and wire the Get dataset items operation into whatever comes next — a Postgres insert, a Slack message, an email digest. Combined with n8n's Schedule Trigger, a daily deals digest is a four-node workflow with no code.
Make offers Apify modules including Run an Actor and Get Dataset Items. Chain them with an Iterator and a Router to split rows by category or savingsPercentageValue, then push high-discount rows into Airtable, Google Sheets or a CMS.
LangChain users can wrap the run-and-read call above in a @tool-decorated function, which turns the whole feed into a single agent tool. Because every row is already typed JSON with fixed keys, the agent can filter and reason over priceToPay, rating and dealEndTime directly — no output parser, no HTML cleanup step, no schema drift between calls.
For scheduled operation without writing any integration code, use Apify Schedules plus a webhook on run success, which posts the dataset ID to your endpoint the moment a run finishes.
Is it legal to scrape Amazon deals?
Scraping publicly available product and pricing information is generally lawful in the US and EU, and this Actor collects only what any visitor to amazon.com/deals can see without logging in. It requires no Amazon account, submits no credentials, and reaches no login-gated, personalised or restricted content.
Everything returned is business and product data — ASINs, titles, prices, discounts, promotion windows, category codes, brand identifiers — plus aggregate review statistics. No reviewer names, no reviewer profiles, no review text, no seller contact details and no customer information are collected, so no personal data is processed. The relevant considerations here are Amazon's Terms of Service and database/compilation rights in your jurisdiction, not data-protection law.
You remain responsible for how you use the data, including any republication, affiliate disclosure obligations and compliance with applicable law. Consult legal counsel for commercial use cases involving bulk data redistribution.
❓ Frequently asked questions
Does the Amazon Today's Deals Scraper work without an Amazon account?
Yes. No Amazon account, login, cookie, session or API key is required, and the input schema has no credential field. The Actor loads the public amazon.com/deals page, harvests the CSRF token Amazon serves inline in that HTML, and uses it to call the public promotions API. The only account involved is your Apify account, used to start the run.
How often is the scraped data updated?
Every run fetches live — there is no cache anywhere in the Actor. The prices, deal states and end times you get are the values Amazon's promotions API returned at that moment. Because deals rotate through the day as promotions start and expire, a scheduled run once or twice daily catches most of the movement; use asin plus dealId as the diffing key between runs.
What happens if a deal expires or Amazon returns no deals?
An expired promotion simply stops appearing in the feed — the Actor exports what is live at run time, so nothing needs cleaning up on your side beyond diffing against your previous run. If Amazon returns no usable promotions at all, the run finishes with an empty dataset and the log line No deals were collected - Amazon returned no usable promotions. If the deals page itself is blocked or serves a shell (HTTP status other than 200, or a body under 20,000 bytes), the run fails with Deals page looks blocked: HTTP <status>, <size> B rather than pretending to succeed with zero rows.
Can I scrape deals from amazon.co.uk, amazon.de or amazon.co.jp?
No. This Actor is pinned to the US marketplace: the promotions endpoint contains the US marketplace ID ATVPDKIKX0DER, the currency-preference header is USD, and there is no marketplace or domain input in the schema. If you need non-US deal feeds, look for an Actor that exposes a domain selector — piotrv1001/amazon-todays-deals-scraper advertises 13 regional Amazon domains on its listing (checked on the Apify Store 2026-07-25 — not measured here).
Can I get more than 500 deals in one run?
No. Amazon's Today's Deals feed exposes a fixed window of 500 promotions and reports totalCount as 500 no matter how far you page, so limit values above 500 are coerced down to 500 with a warning in the log. The schema's maximum of 10000 is there for input compatibility, not because 10,000 rows are achievable. To collect more over time, schedule multiple runs and merge on asin plus dealId.
Why did my run return fewer rows than the limit I set?
Three legitimate reasons, all visible in the log. Non-deal filler tiles — promotions with a title and an ASIN but no deal details and no price — are dropped and never counted or charged. Duplicate ASINs inside the feed are exported once. And the 500-unique-ASIN stop condition counts filler too, so at very high limits the filler eats into the window. The closing log line reports all three at once: Scanned N promotions | dropped M non-deal filler rows | pushed P.
Does this Actor work for AI agent workflows and LLM pipelines?
Yes. It is callable as an HTTP endpoint by any agent framework — start a run through the Apify API, then read the dataset items — so LangChain, LlamaIndex, CrewAI or a hand-rolled tool loop can all use it with a dozen lines of glue. Every record is typed JSON with a fixed 27-key shape and no nesting, so it can be passed straight into an LLM context window, embedded into a vector store keyed on asin, or returned verbatim as a tool result with no parsing step in between.
How does the Actor handle Amazon's anti-bot defences?
It implements exactly three countermeasures, and it is worth being precise about them because there are no others. First, it sends a realistic desktop Chrome user-agent and a matching header set (origin, referer, accept-language) on both the HTML and API requests. Second, it performs the real CSRF handshake — harvesting x-api-csrf-token from the live deals page instead of hard-coding one — which is what the API actually gates on. Third, it validates every response by size as well as status: any body under 20,000 bytes is treated as a block shell, not as data, and is retried up to three times with backoff. The Actor takes no proxy input and launches no browser; it runs on the Apify container's direct connection.
Do I need to configure proxies?
No — and you cannot. There is no proxy parameter in the input schema; the Actor opens a plain aiohttp session with a connection-pool limit of 8 and runs on the direct connection provided by the Apify container. Nothing about proxies, sessions or fingerprints needs managing on your side.
Does it return data in a format LLMs can use directly?
Yes. Typed, normalized JSON with stable field names — no HTML, no selectors, no parsing. Numbers are numbers (priceToPay is a float, reviewCount an integer), absent values are null rather than empty strings or zeros, and the key set never varies between records or between runs. Pass rows directly to an LLM, index them into a vector store, or route them through an agent tool.
How does this compare to other Amazon Today's Deals scrapers?
The observable differences are field depth and marketplace breadth. This Actor returns 27 keys per row including the five-bucket star histogram, glProductGroup, productType and brandId; piotrv1001/amazon-todays-deals-scraper's listing README documents a 12-key sample output and a domain input covering 13 Amazon regional sites (both checked on the Apify Store 2026-07-25 — not measured here). Choose on breadth of marketplaces versus depth of fields per US deal.
What happens when Amazon changes its page structure?
The Actor is maintained, and the output schema is designed to stay stable through those changes: the same 27 keys, the same types, null for anything Amazon stops sending. Extraction is guarded by explicit entity-type checks rather than key-presence checks, so an upstream expansion that starts returning an error node degrades to null on that field instead of corrupting the row or crashing the run.
Your feedback
Found a bug, hit an unexpected null, or need a field this Actor does not yet return? We want to know. Open an issue on the Actor's Issues tab on its Apify Store listing — that is the fastest route, since it is attached to the run you are reporting about. Feature requests for additional deal fields, extra marketplaces or scheduled-run patterns are welcome there too, and they shape what gets built next.
Related searches: amazon deals scraper, amazon today's deals scraper, amazon discount scraper, amazon goldbox scraper, amazon deal of the day API, amazon price scraper, amazon lightning deals data, amazon limited time deal feed, amazon promotions API scraper, amazon deal badge extraction, amazon star rating scraper, amazon review count data, amazon category and brand data, deal aggregator data feed, amazon price drop monitoring, scrape amazon deals without a proxy, amazon deals JSON export.