# Changelog of Amazon Search Results Scraper — Full Product Row, Flat Fee (`steadyfetch/amazon-search-scraper`) Actor

- **URL**: https://apify.com/steadyfetch/amazon-search-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/steadyfetch/amazon-search-scraper.md

## Changelog

### 1.0.57 — 2026-09-19

- **The whole "Maximum cost per run" you set is now spent on products.** Before this build the run held back about a tenth of your cost cap before it started — a cushion for platform running costs which, on this actor's pricing, your cap does not pay for at all: your cap buys products, and the running costs are ours. So the cushion was simply cap you had asked to spend and could not get. On a run capped at $0.10 with products at $0.0015 the plan asked for 60 products where the cap paid for 66 — 6 products of your own cap, unspendable by construction. From this build the plan uses your cap in full, so a run asks for as many products as your cap can really pay for. Nothing you are charged changes, and nothing can be charged above the cap you typed: every charge is still checked against what is left of your cap at the moment it is posted, and a run that reaches your cap still stops cleanly, ships what it had already fetched, and tells you what is left. No price, input field or output column changes.

### 1.0.56 — 2026-09-16

- **The per-product price and a line on how often the data moves now sit in the opening list, three screens earlier than before.** A buyer landing here had to read about 6,928 characters before the price appeared at all. It is now a bullet under the input line: both ends of the tier ladder, the one priced event, and the reminder that a row we could not deliver is never charged — with the full ladder, the event name and the honesty contract unchanged below. Beside it is the cadence line that was not on the first screen at all: what actually moves between one run and the next, so a buyer can tell whether this is a one-off or a schedule. No input field, output column, charged event or price changed; only where the page says them.

### 1.0.55 — 2026-09-13

- **The table of sibling Amazon actors now names the Best Sellers listing by its current title.** That listing is called Amazon Best Sellers Scraper — Top 60 Ranks, Full Product Row: it returns the top 60 ranks Amazon puts in the page, and its old title said every rank. The link here still points at the same actor; only the words a reader sees changed. Nothing else moved: no input field, output column, charged event or price changed.

### 1.0.54 — 2026-09-13

- **The input form now opens on a first run that is 20 products, not 80.** The form arrives with two example keywords, and `Max products per keyword` used to sit empty and fall back to 40 — so pressing Start on the example fetched up to 80 full product rows, about $0.48 on the Apify free plan, and took several minutes. The form now opens with that limit set to 10, so the example run returns up to 20 products for about $0.12 and finishes in a couple of minutes. This is a starting value in the form only: the limit still falls back to 40 whenever it is left out by an API call, a scheduled task or an integration, so nothing you have already wired up changes. Nothing else moved: no input field, output column, event or price changed.

### 1.0.53 — 2026-09-13

- **The input form now opens with the call that works, what one product costs and what is never charged — the screen an AI agent reads.** An AI agent shopping the store never reads this page: it reads the input form's own description, and that description used to open by telling a human to click Start. It now opens with a ready-to-send input, says which field is required and that every other one can be left out, gives the per-product price on the Apify free plan and on paid plans with the per-1,000 arithmetic, says there is no per-keyword fee, lists what is never charged, names the run option that caps the bill and the two limits that bound the work, and points an ASIN, a Best Sellers link or a seller id at the right sibling actor. **Keywords** leads with the value shape and its example instead of the console instruction, which now comes last. Nothing else moved: no input field, output column, event or price changed, and the console form behaves exactly as before.

### 1.0.52 — 2026-09-12

- **An aborted or migrated run now leaves its receipt from the first moment of the run, instead of only after start-up finishes.** The record that says how a run ended was only put in place once the run had finished starting up — reading your input, opening its stores, working out what a previous attempt had already delivered and charged. A run stopped inside that window ended with nothing written about it at all, which mattered most on a re-started run, where the thing not written about was the earlier attempt's work. It is now in place from the run's first moment. Nothing else moved: no input field, output column, event or price changed, and a run that reaches its work behaves exactly as before.

### 1.0.51 — 2026-09-12

- **This actor has a new title on the store: Amazon Search Results Scraper — Full Product Row, Flat Fee.** Same actor, same id, same URL, same input, same output, same price — only the words on the listing changed, so nothing you have saved, scheduled or wired into an integration needs touching. The title now carries the phrase buyers actually search for, which is the only reason it moved.
- **Asking for a bigger limit than this actor can do no longer stops the run before it starts.** `Max products per keyword`, `Max products (whole run)` and `Max run seconds` used to be range-checked by the platform itself, so a run asking for 1,000 results a keyword, 50,000 products or 30 seconds was refused outright: no run, no rows, no message, nothing on the run page to explain it. The ceilings are unchanged (100 a keyword, 5,000 products, 60 to 21,600 seconds) but they are now ours to apply: the run starts, continues at the nearest value it can do, and adds one uncharged `input_note` row naming what you asked for and what bound. Anything you already send inside those ranges behaves exactly as before.
- Nothing else moved: no input field, output column, event or price changed.

### 1.0.50 — 2026-09-11

- **An AI agent can now pin this actor straight from the top of the store page.** The one-click MCP link, the actor's id, the single input field it needs with a real example, and the run setting that caps what a run may spend now sit in the opening lines of the page instead of far down it. An agent that reads only the start of a listing could not see any of that before, so it could not work out how to call this actor without being told. Nothing about the actor itself changed — same id, same input, same rows.
- **The page also names our other scrapers correctly again.** A few links and mentions still used titles those actors no longer have. The links always pointed at the right actors; only the words were out of date.
- **One maintenance detail you will not see:** the private run-report this actor writes for our own support — numbers only, never anything you typed — now also records the price each charged item carried on that run, so a question about a bill can be answered from the run itself.
- Nothing else moved: no price, event, output column or charge changed, and only delivered products are charged.

### 1.0.49 — 2026-09-10

- **A maintenance build: nothing about your runs changes.** The private run-report this actor writes for our own support — counts only, never anything you typed — gained room for four figures it does not fill in yet: how many targets a run was given, how long it waited on a blocked source, how many of those waits recovered, and a reason code for an item our own size limit refused. The build carries the shared contract so a later one can report them; on this actor every one of them is left blank, and nothing a run does or costs is different.
- Nothing else moved: no price, event, output column or charge changed, and only delivered products are charged.

### 1.0.48 — 2026-09-09

- **A run on a short time limit now gets a real second attempt on a blocked product.** Patience is sized to the clock a run actually has instead of being refused whenever the full pause would not fit, so a short run — including the eight-minute sample and Apify's own five-minute health check — gets a retry where before it got none. The first pause is a third as long, so a block that lifts quickly is caught far sooner, and a block that answers the same way twice ends the waiting instead of paying for pauses that were never going to help.
- Nothing else moved: no price, event, output column or charge changed, and only delivered products are charged.

### 1.0.47 — 2026-09-09

- **A search that honestly found no matches no longer asks you whether something went wrong.** A keyword Amazon answered with no results — or whose results your own filters removed — is a real answer, and nothing is charged for it. The run page still ended with "Something off? Open an issue", which reads as a fault on a search that worked. It now asks for an issue only when something a re-run could fix went wrong: a search page Amazon blocked or we could not read, a product row we could not fetch, a setting we could not accept, a run cut short by your cost cap or the clock, or a run that delivered nothing and could not say why. Every count still appears on the line exactly as before.
- Nothing else moved: no price, event, output column or charge changed, and only delivered products are charged.

### 1.0.46 — 2026-09-06

- **A block of links pasted into the keywords box now comes back with an uncharged row saying so.** "Keywords" searches Amazon for words. A whole block of product links pasted into a single row used to be searched as one very long phrase, which can only come back empty. It is now answered before anything runs with a single uncharged row that says how many links it found and where they belong — product links and ASINs are read directly by our Amazon Product Scraper.
- **Your search text is never split apart.** Only you know whether "red running shoes" is one search or three, so nothing is guessed — a row holding words rather than links runs exactly as before.
- Nothing else moved: no price, event, output column or charge changed, and only delivered results are charged.

### 1.0.45 — 2026-09-06

- **The run's own record now counts the results your limits left uncollected.** When your **Max products** cap filled, your maximum cost per run was reached, or the run's clock ended the walk, the keywords still ahead of it — and the results inside a keyword whose page had already been read — were simply absent from the report this run writes back to us: a run that asked for five products and delivered two closed its books with three named by nothing at all. Each is now counted under the limit that stopped it, so a run that stops short of what you asked for is visible to us without you having to report it.
- **A run that stopped at your product cap now also records whether that cap really filled.** It is one true-or-false fact about the run, never the number you typed, and it lets us see a run that claimed your cap stopped it while it had in fact delivered fewer products than you allowed.
- **Nothing you can see changed.** Your rows, your columns, your receipt row and your bill are exactly as they were — only delivered products are charged, and a product that was not delivered is not charged.

### 1.0.44 — 2026-09-05

- **A keyword whose results run out is no longer recorded as if it had returned a full page.** Ask for up to 40 products from a keyword Amazon answers with 16, and this run's own record of the job said you had asked for 40 and been given 16 — 24 products that were never there, and nothing in the record to say so. The record now follows what each keyword really returned. Your rows, your status line and your bill are unchanged: the same 16 products are delivered and charged.
- **A keyword that was never searched is now counted one by one, not as a single problem.** When a setting such as "Marketplace" or "Sort by" cannot be read, every keyword you sent still gets its own uncharged row saying so — that part is unchanged — but our own record of the run counted that as one problem rather than as the eight keywords it cost, so a run of yours that delivered nothing could look far smaller to us than it was. The same is now true of a keyword Amazon walled: the run records the results that wall cost, not just the wall.
- **An empty search box now stays in the count of what you asked for.** If your list held five keywords and one of them was blank, the run's own record quietly dropped it from what you had asked for. It is still answered with its own uncharged row, and nothing is charged for it.
- **Your "Max products" limit is now recorded as what stopped the run, never as what you asked for.** A run that filled your limit reads as a run that filled your limit, with the keywords it never reached still on the record as asked for and unfinished.
- **The same product surfaced by two of your keywords is counted once**, the way it has always been delivered once and charged once.

### 1.0.43 — 2026-09-05

- **A run now pauses only when it can finish a whole second round of attempts afterwards and still have time to write its rows.** When Amazon refuses every route, this actor waits a minute and a half to three minutes and asks again. The check that decided whether that pause was affordable set aside half a minute for the round of attempts that follows it, while a real round here takes between two and a half and just over four minutes, depending on how many routes the run is allowed to use. So on a short run — the automatic five-minute check, or a low **Max run seconds** — the run could take the full pause and then run out of clock part-way through the round it had just waited for. The pause is now measured against a real round on this actor's own connection ladder, so a first run that waits now always keeps room to finish and report: a short run either waits and finishes cleanly or answers straight away, and a run with the time to wait behaves exactly as it did.
- Nothing about your dataset or your bill changed: a pause is never charged, and only delivered products are charged.

### 1.0.42 — 2026-09-05

- **A sentence in the entry below called this actor's sample connection routes "free".** A run always spends platform time you pay for, so nothing on this page is described that way: the sentence now says the no-input sample uses only the unpaid connection routes. Nothing about what this actor does, delivers or charges changed.

### 1.0.41 — 2026-09-05

- **A run started with no input at all now waits out a block like any other run.** Press Start on the untouched form and this actor runs one real search, charged like any run. Until now the no-input sample was the one run that never paused: its time limit was three minutes, and one pause of a minute and a half to three would have used most of it. So the most common first run of all — a first-time buyer pressing Start, an agent sending nothing, the daily automatic check — reported "blocked, please re-run" while the block was still lifting. The sample's time limit is now eight minutes, sized to hold one full round of attempts, one pause, another full round, and enough time left over to stop cleanly and report, and the sample is patient like everything else. A sample Amazon answers still finishes in seconds; only a blocked one uses the extra time; the no-input sample still uses only the unpaid connection routes, so a wait never buys a paid one; and nothing is charged unless product rows are delivered.
- **How much of its remaining time a blocked run may spend waiting now follows the size of what you asked for.** A run with more searches still to make keeps exactly the limit it had — no more than half the time left — so a wide block still leaves the later searches their share of the run. A run with a single search may spend what is left on its one pause, because nothing else is waiting for that time.

### 1.0.40 — 2026-09-05

- **A search or a product Amazon walls is now waited out inside your own time budget, instead of being handed straight back for a re-run.** Until now a keyword Amazon refused on every route, and every product page it refused, ended after one climb of the connection ladder — well under a minute — and shipped an uncharged "please re-run" row while most of a long run's time went unused, on a wall that usually lifts within minutes. Now, while the run still holds real time and the work still waiting can pay for the idle minutes, the run waits a minute and a half to three, takes fresh network routes and tries everything it held again — and only then ships the honest rows, which now say what was tried: how long the run waited and how many passes it made. A search or product that answers after a wait delivers exactly as before, charged once.
- **What never waits:** a real "no products matched", a page our own sponsored filter emptied, a "page not found", a layout we could not read, a foreign-catalogue or subscription page, and the run's own row, time and cost limits — those are answers, and a wait cannot change them. The no-input sample run never waits either: it has three minutes to show you real rows, and a wait would spend most of them.
- **Short runs are unchanged.** A wait and a fresh pass have to fit inside what the run has left, with time kept back to finish and report, so a 60-second run makes its one pass exactly as before.
- **Held rows arrive after your delivered rows**, in the order you sent your keywords, so the dataset still reads top to bottom. The summary row carries what the waits bought — passes, seconds waited, how many walls lifted — and the run log says it in one line.
- **Charges are unchanged:** waiting is uncharged, a refused search or product is uncharged, and only delivered products are charged.
- **The run's own record now tells a walled search apart from an empty one.** A keyword Amazon refused used to be counted exactly like a keyword with no matches, so a wall was invisible to us; it is now counted separately as well. Nothing about your dataset or your bill changed.

### 1.0.39 — 2026-09-05

- **A run near its time limit now stops cleanly instead of being cut off mid-fetch.** The page-fetch ladder now checks the run's own clock before every attempt and every pause between attempts, so it never starts a fetch it cannot finish in time. A run that reaches its limit ends with its summary row intact rather than being stopped part-way through a request.

### 1.0.38 — 2026-09-04

- **Every run now reports what you asked for in the same unit it reports what it delivered.** The run's own record counted your ask in *keywords* while it counted the result in product *rows*, so a run that searched two keywords and came back with forty products recorded an ask of two — an ask smaller than its own delivery. Your ask is now the row cap you set in "Max products (whole run)", or, when you set no cap, the keywords you sent times "Max products per keyword". The summary row is unchanged: it still counts the keywords you asked for, and says so. Nothing about what is collected, delivered or charged changed.

### 1.0.37 — 2026-09-04

- **Settings with no keywords now run the sample search under your settings, instead of returning one guidance row.** Picking a different **Marketplace** or **Sort by**, typing a **Department**, turning off sponsored results or setting a limit and clicking **Start** with **Keywords** empty used to end the run with a single uncharged "no keywords were provided" row — so changing one dropdown was answered worse than changing nothing at all. That run now searches for the sample keyword with your settings applied, charged like any run.
- **A limit is a ceiling, never a request.** On one of these runs "Max products per keyword", "Max products (whole run)" and "Max run seconds" are honoured as *at most* — the sample's own five products and three-minute window are used when they are smaller, so narrowing a setting can never widen the bill.
- **One uncharged row explains it**, naming every setting you did set, that everything else used the sample's own values, and the field to fill in for your own run. It is never counted as a miss.
- **A field this actor does not recognise, or a keyword list you actually filled in, still gets the guidance row** — answering a typo with sample rows would read as if it had worked. A store or a sort order this actor does not offer is still refused by name.

### 1.0.36 — 2026-09-04

- **A mistyped "Marketplace" or "Sort by" no longer swallows your keyword list.** One unreadable value in either field used to end the run with a single guidance row, whatever you had typed in "Keywords" — twenty keywords came back as one row. Every keyword you sent now gets its own uncharged row saying it was not searched and which field stopped it, and the run still succeeds. Nothing is searched and nothing is charged, exactly as before.
- **"Marketplace" now says which of three things went wrong.** A real Amazon store this actor does not cover (amazon.ca, amazon.fr, amazon.co.jp and the rest, plus the country names people type for them) names the nearest store that does work, instead of sending you back to re-check a spelling that was already right. A value naming more than one store — "worldwide", "Europe", or just "amazon" — says this actor reads one store at a time. Only a value nothing can read is now reported as unreadable.
- **Every uncharged input row now carries the field it is about**, so a run with several settings set says which one to fix without reading the sentence.
- **The delivered total on a restarted run is the whole run's again.** A run the platform moved to another server reported only the products the second server delivered; it now reports every product the run delivered, matching the summary row and the three sibling actors.
- **The run's own report to us now carries the size of your ask** — the keywords you typed, counted before any limit applies. It used to report whichever list in your input happened to be longest, so a run that turned every keyword away could look like it had nothing to do.

### 1.0.35 — 2026-09-04

- **A store written the ordinary way now works in "Marketplace".** The field used to take the exact domain and nothing else, so `US`, `USA`, `United States`, `Amazon.com`, `www.amazon.com` and a pasted store link each stopped the run before a single keyword was searched — one guidance row, and nothing for anything you sent. The domain, the host, a pasted link, the country code and the country name all resolve now. A store this actor does not cover is still refused rather than answered with a different one.
- **"Sort by" reads the value you actually sent.** `Price: low to high`, `price_asc`, `cheapest`, `Newest arrivals` and `rating` now land on the order they name, instead of stopping the run as an unrecognised value.

### 1.0.34 — 2026-09-04

- **A run stopped by an input mistake now tells us which field was wrong** — the field's name only, never the value you typed. A check that is too strict now reaches us as one thing to fix instead of looking like many unrelated typos.
- **A product page that was blocked or unreachable is now counted apart from a product that genuinely is not there**, so a wave of blocks reaches us as one thing to fix instead of reading like missing products. Your rows and your prices are unchanged.

### 1.0.33 — 2026-09-04

- **A search page that comes back unreadable is now retried before it is reported as a miss.** A page that arrives complete but with none of the results on it used to end the attempt right there. The run now takes another look — a different page layout, a different network route — and reports a miss only if those come back empty too. Same price either way.

### 1.0.32 — 2026-09-04

- **A run that stops before it starts now reports its outcome too** — a run refused for its memory setting now reaches us the same way every other run does: counts and reason codes only, never your input or your rows.

### 1.0.31 — 2026-09-04

- **Every run now reports its own outcome to us** — counts and reason codes only, never your input or your rows — so a run that goes wrong reaches us even when nobody shares it.

### 1.0.30 — 2026-09-04

- **Run status lines fit the run page again; sample-run wording shortened.**

### 1.0.29 — 2026-09-04

- **A run stopped by a pricing fault on our side now asks you to open an issue once, not twice**, and names the reply time.

### 1.0.28 — 2026-09-04

- **A run that filled the row cap you set is no longer treated as a run that went wrong.** The Issues-tab line now appears only when something actually did.

### 1.0.27 — 2026-09-04

- **The run page points at the Issues tab on every ending that went wrong**, including a run refused before it started.
- **One support promise on this page** — the older three-hours line is gone.

### 1.0.26 — 2026-09-04

- **A run that ends with a problem now says where to reach us.** A miss, an input error, an early stop or a failed run closes by pointing at the Issues tab and naming the reply time; a fully delivered run is left alone.
- **One support promise across this page** — issues are answered in a couple of hours, always within a day.

### 1.0.25 — 2026-09-03

Documentation build: nothing about what runs, what is delivered or what is charged changed.

- **The screenshots on this page now load from Apify storage.** The same two images of a real run, served from the platform itself instead of an outside host.
- **Every link on this page now stays inside Apify.**

### 1.0.24 — 2026-09-02

Documentation build: nothing about what runs, what is delivered or what is charged changed.

- **Real console screenshots on this page** — the input form exactly as it arrives, and the dataset table a real run delivers.
- **One-click MCP link** — pin this actor in Claude, Cursor or any MCP client straight from this page.
- **Suite links refreshed** to the current names of the other steadyfetch actors.
- **Input-form copy corrected.** The Keywords field still said a bare Start returns uncharged sample rows. It runs a real sample search, charged like any run — the field now says so, as this page already did.

### 1.0.23 — 2026-09-02

Start with the default form and get real products instead of placeholder rows.

- **A bare Start now runs a 5-product sample search.** Click Start with nothing set (or send an empty input from the API) and the run searches `amazon.com` for `wireless earbuds` and returns up to five real product rows, charged like any other products. The placeholder "sample rows" are gone; what you see is what a real run returns.
- **The sample stays small and quick by design:** one keyword, five products, the no-cost connection lanes only, and a three-minute window. On a bad Amazon minute you get one uncharged row saying the search was not served (re-run in a minute), never an empty dataset.
- **The status line says when a run was the sample** and how to run your own keywords.
- **Nothing else changed:** any input with keywords in it behaves exactly as before, and a mistyped field still gets a row naming the field instead of a sample.

### 1.0.22 — 2026-08-31

The `Marketplace` and `Sort by` dropdowns accept `null` as well, so an all-fields-null template runs.

- **An input that fills every optional field with `null` now starts.** That is the shape n8n, Make and most agent frameworks actually send, and two fields were still refusing it: the `Marketplace` and `Sort by` dropdowns. `{"keywords": ["coffee maker"], "marketplace": null, "sortBy": null, "maxItems": null}` used to be rejected before the run began, with an error about allowed values. It now runs on the defaults — amazon.com, Amazon's own Featured order — exactly as if those fields had been left out.
- **A value the dropdown does not list is answered by name, and nothing is searched.** `"marketplace": "amazon.ca"` or `"sortBy": "price-ascending"` returns one uncharged row naming the values that do work. Neither is quietly swapped for the default: US rows under a Canadian question, or Featured order under a cheapest-first question, look exactly like the answer you asked for. Nothing is charged, and the run still succeeds.
- **Every value the dropdowns list behaves exactly as before**, and the console pickers are unchanged.
- **The run's own status line now says "1 input error" instead of "1 blank keyword skipped".** A mistyped `sortBy` was being reported as a keyword problem, which sent you looking at the wrong box; the dataset row has always named the right one.
- **Nothing about what is delivered or charged changed.** One flat fee per delivered product, misses never charged.

### 1.0.20 — 2026-08-31

Optional settings now accept `null`, and `null` means "use the default".

- **An explicit `null` on an optional setting starts the run instead of refusing it.** Agents and integrations routinely fill in the fields they are not using with `null`; until now `{"keywords": ["coffee maker"], "maxItems": null}` was rejected before the run began, with an error saying the field had to be an integer. It now runs exactly as if the field had been left out.
- **`null` never changes what a run does.** `Max products per keyword`, `Include sponsored results`, `Department`, `Max products (whole run)`, `Max run seconds`, `Include variants` and `Include specifications` each fall back to the same default they would have used anyway. This is a second way to say "leave it alone", not new behaviour.
- **`Keywords` still cannot be `null`, and neither can the `Marketplace` and `Sort by` dropdowns** — a dropdown only accepts one of the values it lists. Send a real value or leave the field out entirely. `Keywords` staying strict is deliberate: it is what catches a mistyped field name before the run starts rather than after.
- **Nothing about what is delivered or charged changed.** One flat fee per delivered product, misses never charged.

### 1.0.19 — 2026-08-31

Results now arrive in Amazon's own result order.

- **Rows land in rank order.** The `searchRank` column is what this actor sells — the page had always been read correctly, but the two fetch lanes each wrote their row the moment that product finished loading, so a run could hand you 2, 1, 3, 4, 6, 5 instead of 1, 2, 3, 4, 5, 6. Rows are now written in rank order, keyword by keyword, so the dataset reads the way the Rank column says it does.
- **An uncharged miss keeps its own rank.** A product Amazon would not serve still ships as a `charged: false` row, and it now sits at its own position in the list rather than at the end, so the ranks around it stay unbroken.
- **Nothing else moved.** Rows still stream in as the run goes (a run the platform moves to another server keeps everything already written), the two lanes still fetch in parallel, and what is charged is unchanged: one flat fee per delivered product, misses uncharged.

### 1.0.18 — 2026-08-31

The linked sample dataset is re-shot from the code this release ships, and it now has a permanent address.

- **The sample-dataset link points at a fresh run of exactly this code** — `coffee maker` on amazon.com, two delivered rows with the Sold-by cluster populated, and the summary row last.
- **That sample now lives at a permanent address.** It used to be one run's own output, which is cleared when that run ages out — the link would eventually have gone dead on its own. It cannot now.
- **The page says "a verified run of the current code", not "of the current build"**, because a release that changes only this page must not make that sentence false. Nothing about what this actor delivers or charges changed in this release.

### 1.0.16 — 2026-08-30

The linked sample dataset is re-shot from a verified run of the current build.

- **The sample-dataset link now points at a run of this build** — `coffee maker` on amazon.com, two delivered rows with the Sold-by cluster populated, and the summary row last. An amazon.co.uk search was also verified end-to-end on the same build. Nothing about what this actor delivers or charges changed in this release.

### 1.0.15 — 2026-08-30

The Sold-by seller is populated again, amazon.co.uk searches deliver again, and absences explain themselves.

- **`buyBoxSeller`, `buyBoxSellerId`, `fulfilledByAmazon` and `soldByAmazon` are filled in again on delivered product rows.** Amazon serves the Sold-by block in several layouts and rows had been shipping the cluster as null; the parser now reads all of them, verified against freshly captured pages.
- **amazon.co.uk searches deliver again.** The .co.uk site had begun refusing every desktop browser fingerprint on every route we use — a whole .co.uk run could end with zero rows. The fetch ladder gained one final mobile-fingerprint step on the same residential exits; a .co.uk search page was fetched and parsed end-to-end the same day. Blocked keywords are still never charged.
- **New column: `buyBoxNote`.** When a served page genuinely names no seller, the Sold-by fields stay null and this column says so on that exact row.
- **Amazon's own device pages now deliver their specs**, and invisible direction marks (the `&lrm;` garbage some exports showed) are stripped from every text field.

### 1.0.14 — 2026-08-30

Clearer release notes — this page's notes now read more plainly. Nothing about what this actor delivers or charges changed.

### 1.0.13 — 2026-08-30

Suite links now point at the full live shelf — every actor named in this README is a live
store link. Nothing about what this actor delivers or charges changed.

### 1.0.12 — 2026-08-30

Restarts, resurrections and billing bookkeeping hardened end to end.

- **A restarted run no longer trusts a stale answer about what it already delivered.** Right after a restart, the platform's view of the run's own output can lag a few seconds behind. A run that believed that lagging answer could have delivered — and charged — products a second time, or lost count of rows past the lagging total. It now double-checks an "empty" answer and reads its own output through to the true end before doing anything, so nothing already delivered is ever fetched, delivered or billed again.
- **Rows that can only be written once are written once per run, not once per restart.** The verdict row for a permanently-missing product and the row answering an invalid keyword used to be repeated by a restarted run — which also re-fetched every permanently-missing product before repeating its verdict. Both are now remembered across restarts: reported once, never re-fetched, and never charged either way.
- **Finishing an interrupted charge can never bill twice — and can never sink the run.** When a restart finds a charge from the previous attempt half-finished, the amount still owed is reckoned against the highest count of what already landed, so a lagging counter cannot cause a repeat charge. And if that settlement cannot be completed at that moment, the run carries on and settles it on a later resume instead of failing — nothing extra is charged either way.
- **A run being moved to another server hands over cleanly.** The departing side no longer declares the run finished on its way out — the run continues where it left off.
- **A resurrected run gets a real working window.** "Max run seconds" counts the run's life, not each restart's — but a run resurrected after that window had already passed used to stop on its first step, blaming your own limits, with nothing new delivered. It now gets a fresh, bounded window to finish the remaining work.
- **If this actor's own price configuration is ever broken, a run stops before spending anything.** Both broken shapes — one that would bill for rows we promise carry no result fee, and one that could not bill at all — halt immediately, fetch nothing, charge nothing, and say plainly that the fault is ours.
- **A charge is counted only when it actually landed.** The `charged` flag and the run's own charge totals now reflect the platform's answer, never an assumption.

### 1.0.11 — 2026-08-29

Numbers printed in the "wrong" language now always read as the numbers they are.

- **Counts survive a product page served in another language's number format.** Amazon renders a page in the formatting of the route that fetched it, not the store's own, so amazon.de sometimes arrives with English-style numbers — a review count of "4,305". Read with German number rules that used to collapse into a decimal: a charged `reviewCount` of 4, a thousand times under. Grouped whole numbers now read as grouped whole numbers in every language — on review counts, bestseller ranks and prices alike.
- **"Bought in past month" badges phrased without a "+" right after the digits parse correctly**, and the localized German thousand/million marks ("Tsd.", "Mio.") are understood — "Mehr als 1.000 Mal … gekauft" is 1,000, never 1,000,000.
- **A Nordic "kr" price mark never takes another marketplace's currency label.** When the currency of a price cannot be resolved from the page, the `currency` column ships honestly empty instead of guessed.
- **The Amazon suite links in the README now point at the published actors.**

### 1.0.10 — 2026-08-29

A typo in an input field name now gets a helpful pointer instead of sample rows.

- **A run that sets a field this actor does not have is answered, not demoed.** Sending something like `keyword` instead of `keywords` used to look exactly like an empty run, so it came back with the uncharged sample rows — and nothing said the field had been ignored. Such a run now returns one uncharged row that names the field it did not recognise, names `Keywords` (input field `keywords`) and shows the shape to send. Changing a setting such as the marketplace without entering a keyword is answered the same way. A run that really is empty still returns the sample rows, and a run with real keywords is unchanged.

### 1.0.9 — 2026-08-29

"No matches" now means Amazon really said so.

- **A keyword is never reported as having no matches on the word of a request Amazon distrusts.** Amazon sometimes serves a full "no results" page to a request it does not trust, for a search that in fact has plenty of matches. Such a page is now re-checked before any verdict is given, and if that re-check never succeeds the row says the search could not be completed this run and asks you to re-run — uncharged — instead of telling you your keyword has no matches.
- **A results page we cannot read is reported as our problem, not yours.** If Amazon serves a real results page in a layout this actor cannot parse, the row now says so and is flagged for us to look at, rather than claiming the search returned nothing.
- **A search emptied by your own sponsored filter says exactly that.** If Amazon answers with products but every one of them is a sponsored placement and the run was set to skip those, the row now names the filter and tells you to re-run with sponsored results included — instead of reporting no matches.

### 1.0.8 — 2026-08-28

Price parsing is hardened, ported from the family's shared parser.

- Promotional wording printed next to a price ("avec 18 % d'économies", "con il 18 % di risparmio") can no longer bleed its digits into the parsed amount — a percentage is never read as part of a price, in any language.
- The Nordic "kr" and Polish "zł" currency marks are now recognised wherever Amazon prints them, instead of being dropped.
- **Review counts on European listings are read correctly.** Some storefront layouts print the total with a space between the digit groups ("4 298"); earlier builds could not read that formatting and shipped an honest empty `reviewCount`. The count now arrives as a number, in the store's own formatting.

### 1.0.7 — 2026-08-27

Your product limit is exact again, and one figure was ten times too large.

- **"Max products (whole run)" holds when two products finish at the same moment.** The actor works on two products at once, and the limit used to be counted after a row had already been written. Two products landing together could both pass a limit that had one slot left, so a run capped at 50 could hand you 51 rows and charge for 51. The slot is now claimed before the row is built, and a product that cannot claim one is never fetched, delivered or billed.
- **A restarted run no longer stops short of your limit.** A run that picks up where it left off counts what it has already delivered against your limit. Rows that are not products — misses, invalid keywords, the summary row — were counted as well, so a resumed run could finish with noticeably fewer products than you asked for. Only delivered products count now.
- **"Bought in past month" is correct on decimal counts.** Amazon writes some of these as `1.5K+`, and as `1,5K+` on amazon.de. Both were read as 15,000 instead of 1,500 — ten times the real figure. Whole-number forms such as `2K+` and the German `1.000+` were always right and are unchanged.

### 1.0.6 — 2026-08-27

Restart safety: a run that moves servers, or that you resurrect, never delivers or charges the same product twice.

- **No double charges after a restart.** Apify can move a long run to another server mid-flight, and resurrecting a finished run is one click. Either way the run used to start over from an empty memory: products you had already received were fetched again, written to your dataset a second time, and **charged a second time**. Every delivered row now carries an invisible record of what it was and what it cost, so a restarted run reads its own dataset first, skips everything already delivered, and finishes only the charge that was interrupted. Same run, same dataset, one row and one charge per product.
- **Your product limit holds across a restart.** "Max products (whole run)" counted only what the *current* server had delivered, so a run that moved could deliver up to twice the number you asked for. The count now starts from what the run has already delivered.
- **"Max run seconds" is measured from the run, not from the server.** A run that moved used to get a fresh full allowance on the new machine.
- **A blocked search is no longer reported as "no results".** When Amazon answers a search by redirecting to its sign-in or robot-check address, the page it serves has no results on it — that used to be read as "your keyword matched nothing", which is permanent and wrong. It is now the retryable `blocked` row it always was, and the run spends nothing more trying to force it.
- When a run is being moved, work already in flight is dropped rather than half-delivered, and the summary row says so instead of blaming one of your settings.
- **A new honest status, `not_a_product`.** Amazon sells some of its own subscription plans through ordinary product addresses. Those pages are fine — they simply are not product listings, and they have no price, seller or reviews. They used to come back as `parse_failed` ("a layout we could not read, that one is on us"), which was a false confession. Never charged, either way.

### 1.0.3 — 2026-08-27

Review-fix build: charge-once dedupe, permanent "page not found" honesty, and a tighter spend clamp.

- **Billing accuracy.** Two search results that turn out to be the same product — different result cards that redirect to one canonical page — are now delivered once and charged once, even when they are fetched at the same moment. Before, both could slip past the duplicate check while the first row was still being written, and you could pay twice for one product.
- A row that fails to save no longer counts as delivered: its charge slot is handed back, so the run's invoice always matches the rows you actually received.
- **Honest verdicts.** A search address Amazon answers with "page not found" now comes back as a permanent `not_found` row that says so and tells you to check the keyword and any department filter — instead of a "this is temporary, please re-run" message for a page that will never exist. It is also no longer retried through every fallback, so a dead address costs nothing to discover. Still never charged.
- **Spend clamp.** The actor no longer fetches extra search pages it has no budget left to deliver products from, and a run that spends its last charge on the final keyword now correctly names your spend cap as the reason it stopped.

### 1.0.2 — 2026-08-27

Initial release.

- Type Amazon search keywords and get one complete product row for every result: the keyword, its search rank, whether it was sponsored, plus price, currency, list price, stock, buy-box seller, rating, review count, bought-in-past-month, variants, bestseller ranks, category path, images, bullet points and the specifications table.
- Full product detail on every result — there is no cheaper "listing only" mode, because that would need a second event and this family charges one.
- Marketplaces: amazon.com, amazon.co.uk and amazon.de. Search is verified end to end on amazon.com.
- One priced event per product and nothing else — no start fee, no per-keyword fee, no per-field fee.
- Sponsored results are flagged and can be skipped; a skipped sponsored result is never fetched, so it costs nothing.
- Keywords that return nothing or are blocked, and individual results that cannot be fetched, are returned with an honest status and are never charged, and every run ends with a summary row that reconciles against the invoice.
- Your limits are exact: the run stops cleanly, names the setting that stopped it, and hands back the keywords still to do.
