# Changelog of Amazon.ca Product & Trending Tracker (`akhil_rajesh/amazon-ca-product-trending-tracker`) Actor

- **URL**: https://apify.com/akhil_rajesh/amazon-ca-product-trending-tracker/changelog.md
- **Full Actor documentation**: https://apify.com/akhil_rajesh/amazon-ca-product-trending-tracker.md

## Changelog

### 2026-10-10

#### 0.1.44 - README: how reliable Amazon.ca's lists were this week

- The README no longer calls lists the most reliable mode: it gives the measured share of default runs that got
  Amazon.ca's list from Apify's servers on 2026-10-09 and 10-10 (6, 7 and 3 of 10, then 6 of 6), and what a run does
  about robot checks. Same code as 0.1.43.

#### 0.1.43 - More patience for a list's first page, less for page 2

- A list's first page, a run's way in, is now asked for up to 11 times (about three and a half minutes of waits)
  as a new visitor each time, up from 8 (about two minutes). On 2026-10-10 Amazon.ca refused 7 of 10 default runs'
  eight tries from Apify's servers, and the runs that got the list did so after 4 and 7 refusals. Page 2 goes back
  to 4 tries, so a run that waited out its first page still ends inside the 5 minutes Apify's daily Store test
  allows. The Actor still never answers a robot check.

### 2026-10-09

#### 0.1.40 and 0.1.41 - More patience with robot checks on list pages

- A list page, a run's way in, is now asked for up to 8 times over about two minutes (was 4 times over about
  17 seconds), each time as a new visitor, after waits of 2, 4, 8, 16 and then 30 seconds. On 2026-10-09 Amazon.ca
  answered Apify's servers with robot checks far more often than the day before: 6 of 10 default runs failed with
  4 tries, and 3 of the 4 runs of this build that got the list did so on their 5th to 8th try. The Actor still never
  answers a robot check; it waits and asks again.
- README: keyword suggestions are named with lists as the most reliable mode; the form's change-tracking fields
  mention keyword suggestions.

### 2026-10-08

#### 0.1.37 and 0.1.38 - Keyword suggestions, price history, run summary

(0.1.38 is the same code with the README's measurements from Apify's servers.)

- **Keyword suggestions mode.** The keywords Amazon's search box suggests for each keyword, in its order, on all 23
  marketplaces, from Amazon's own suggestion service with each marketplace's id (Amazon.ca's differ from
  Amazon.com's). **Expand each keyword** adds the keyword followed by a to z, or a to z and 0 to 9: "nappies" on
  Amazon.co.uk gave 344 keywords, イヤホン on Amazon.co.jp 343. Each suggestion is one row, with what was typed
  (`prefix`) and its place in the box; change tracking marks new, moved and dropped suggestions.
- **Price history.** Lists, searches and products keep their last 30 price readings (**Price history: runs to
  keep**, up to 365), and each row shows `lowestPrice`, `highestPrice`, `averagePrice`, `atLowestPrice`,
  `priceReadings` and `priceHistory`, counted in the row's currency only. A product with Only changes on and nothing
  to report now has its record updated too (its price and the run's time), so quiet days count in its history.
- **Run summary.** Every run saves `RUN_SUMMARY` in its key-value store, linked from the Output tab: the outcome
  (succeeded, partial, failed, stopped), each list's, search's or keyword's outcome with rows read and delivered,
  what failed and why, refusals by kind, and the run's times. A pipeline can check a run without reading its log.

#### 0.1.24 to 0.1.36 - Delivery address

- **Prices where Amazon withheld them.** Where a product page comes without a local delivery address or with its
  price withheld ("add this item to your cart to see its details"), the Actor sets the marketplace's main city
  through Amazon's own location dialog, as any visitor can without signing in, and reads the page again. On
  2026-10-08 the same 12 to 13 products had prices on 48 of 73 rows over six runs with the step, and on 16 of 50
  over four runs without it, read at the same moments (Amazon.co.uk, .de, .es, .it, .co.jp, .com.au, .com.tr and .sg
  gained them in one run or another). Where Amazon took the postcode and still showed the page without it
  (Amazon.co.uk, .com.tr, .it at times), the run says so. **Delivery postcode** sets
  your own postcode on the chosen marketplace; **Set a delivery address where Amazon shows none** turns the step off.
  A step that fails (a robot check, a dialog that only asks to sign in) is named in the status message.
- **Prices in each marketplace's own currency.** Amazon.co.uk showed Apify's servers converted dollars (USD65.99);
  the Actor now asks for pounds, euros and so on, as Amazon's currency preference.
- **Each marketplace has its own visitor (session).** A refusal on one Amazon site no longer starts a fresh visit on
  the others, which dropped an address just set on another marketplace.

#### 0.1.19 to 0.1.23 - Subcategories, 23 marketplaces, better reviews

- **Subcategories in one run.** Subcategories reads each list's subcategories as Amazon's list page names them
  (one level, or two), each a list of its own with `subcategoryLevel` and `parentCategoryName`. Amazon.ca's
  Electronics has 15. **All departments** (or a pasted overview link such as https://www.amazon.ca/gp/bestsellers/)
  reads every department of a marketplace. **Max results per list** sets each list's top N; Max results is still
  shared over all the lists, and a run stops looking for more lists at as many as Max results covers, and says so.
- **Thirteen more marketplaces, 23 in all:** Australia, Brazil, the Netherlands, Sweden, Poland, Türkiye, Belgium,
  Ireland, Singapore, the United Arab Emirates, Saudi Arabia, Egypt and South Africa. Prices, ratings, Best Sellers
  Ranks, review dates and countries are read in each one's own words, from pages captured on Apify's servers, and
  the 38 categories are mapped from each marketplace's own department list.
- **Reviews:** a star filter (positive, critical or single stars), verified purchases only, newest or most helpful
  first, the reviewer's pictures (`reviewImages`), a summary row per product (rating, ratings, star breakdown,
  Customers say, and how many reviews the page showed and matched), and **Also read reviews on** other marketplaces:
  each shows other reviews of the product, and a review shown on several is returned once.
- **Pages Amazon serves with parts left out are named, not read as empty.** Some visits get a product page without
  its lower half (rank, description, full specifications, reviews): 7 of 20 pages from Apify's servers on
  2026-10-08, and the Amazon.de, .it and .in pages of 2026-10-06. Such a page is asked for once more as a fresh
  visitor (none of 8 retries on the platform brought the whole page, so not more often); a product row that still
  lacks it is marked `partialPage`, and a reviews run says the reviews didn't load instead of "no reviews" (release
  1 reported those products as having none).
- **Withheld prices and the delivery address.** Where Amazon picks no delivery address for a visit ("Select delivery
  location": Amazon.com, .co.uk, .nl and .com.tr from Apify's servers), product pages show "add this item to your
  cart to see its details" instead of a price: such rows say `priceHidden`. Every product row now has
  `deliveryLocation`, the address Amazon showed the page for ("Deliver to United States" made Amazon.com.au products
  "Currently unavailable").

#### 0.1.17 - Only changes, richer product rows, search filters

- **Only changes:** a scheduled run can output, and charge for, only what changed since the last run: new
  products, moves, price and stock changes, and products that dropped off a list or search (with their previous
  rank). Limits set what counts (1 place, 1% of the price and 10% of a Best Sellers Rank by default); a smaller
  move keeps the last reported value as the baseline, so a slow slide is reported once it adds up. Every tracked
  row now says its `movement` and lists its `changes`, and list and search rows have `priceChange` too. Max results
  is how many ranks are watched; products that dropped off come on top of it.
- **Product rows:** all gallery images, every variant with its ASIN and attributes, the parent ASIN, the
  description and "From the manufacturer" text, the star breakdown, Amazon's "Customers say" summary and its
  aspects (sentiment, mentions), coupon, discount %, Amazon's Choice, the #1 Best Seller badge, other offers and
  their lowest price, and the number of videos. Read from pages of all ten marketplaces.
- **Search:** sort order and price range, and pasted Amazon search links keep their own filters (star rating,
  Prime, brand, department) without Amazon's tracking parameters. A filtered search is tracked apart from the
  plain keyword (`searchFilters`). Search rows show coupons and discount %.
- **Product details for list and search rows:** one switch adds each product's page to its row (only for changed
  rows with Only changes); a page that didn't load leaves its row as it was, and the status message counts them.

#### 0.1.16 - Pricing

- **Platform usage is included.** Runs no longer charge compute on top of the row price ("Pay per event + usage"
  is off). Rows cost $1.00 per 1,000 on the Free and Starter plans, $0.90 on Scale and $0.80 on Business and
  above. The README's cost section says so; the code is unchanged.

### 2026-10-06

#### 0.1.15 - Production pass

- **A page that can't be read fails the run.** A list page whose products can't be read, a results page with
  neither results nor Amazon's "No results" message, another page in a product's place, or a pasted link that
  isn't a list each failed silently before ("Nothing found", SUCCEEDED, or rows quietly missing). They are now
  named, and a run that got nothing that way fails, so a layout change on Amazon can't pass as an empty day. The
  message tells such pages apart from robot checks.
- **A search is empty only when Amazon says so** (its "No results for your search query" message, captured from
  the platform).
- **The run stops a minute before its timeout** and says what it read, instead of being cut off without a word.
- **Change tracking:** a run that reads fewer ranks than the last one (a quick top-10 test) no longer replaces a
  deeper snapshot younger than two days, which left ranks 11-100 "can't tell" on the next daily run. Each product
  has its own record: one shared record per marketplace let two schedules erase each other's products. A stored
  record holding 52.0 or true no longer makes a row the dataset refuses.
- A request in flight stops at once when the run is stopping.
- **Pages cut short are asked for again.** When one of two pages loading at once met a robot check, the fresh
  session for its retry closed the shared connection, and the other page arrived cut short as an HTTP 200: a
  product without its price or rank, or without its reviews. A session now closes only when no page is loading on
  it, and a page that doesn't reach its end is asked for again.
- **Resumed runs stay within Max results.** A run restarted after a kill or a move, whose list or search had
  reordered meanwhile, could add its new top rows to those already delivered, and charge them. Each list, search
  or product now keeps to its share, earlier attempts included, and the run never passes Max results. A resumed run
  also records the products the earlier attempt delivered but didn't get to record.
- **Reviews are saved as they are read**, not after the last product page, so a stop, a move or the spending limit
  keeps what was read.
- **Change tracking:** a price is compared only in the same currency (Amazon.com shows prices in the visitor's
  currency), a Best Sellers Rank only within the same category, and a price or rank a page didn't show keeps the
  last one known instead of erasing it. Product records of 0.1.14 compare as a first run.
- **Lists:** page 2 is asked for whenever page 1 lists 50 products, not only when it links a page 2; Amazon's empty
  grid or HTTP 400 there ends the list at 50. A damaged entry list keeps the 30 products shown and names the rest,
  and an empty grid without Amazon's own "there are no best sellers" words fails instead of reading as nothing
  listed.
- **Input:** `smile.amazon.com` and `m.amazon.de` links work; links to other sites (Amazon.com.au, Amazon.nl...) are
  skipped and named instead of being read on the chosen marketplace; two links on one line are two products;
  `{"url": ...}` items work in Category links and Products; a History name of spaces means the default; products
  past Max results are named.
- **Robustness:** a page the parser chokes on fails its list, search or product, named, instead of crashing the
  run, and any unexpected error ends the run FAILED with a message. Another page in a page's place is asked for
  again once as a fresh visitor. HTTP 400 for a product counts as not found. Rows read before the timeout stop are
  delivered.
- **Proxies:** only the first of several own proxies is used, and the run says so: it never switches addresses to
  get past a refusal.
- **Pay-per-event:** a run whose result event can't be charged says so in its log, and the spending limit is still
  followed through the per-row price.

#### 0.1.11 to 0.1.14 - Whole lists, ten marketplaces read right, change tracking

Checked against live pages of all ten marketplaces, then rebuilt. Nothing below was guessed: every page layout,
price format and category name was read from Amazon's own pages (tests/fixtures).

What the first version got wrong:

- **Lists stopped at 30 of 100.** Amazon shows ranks 1-30 on the page and loads 31-50 and 81-100 as you scroll.
  The Actor now makes the same requests and returns the whole top 100.
- **Prices were empty outside Canada.** "£14.16", "5,89 €", "CAD 17.08" (Amazon.com to a Canadian visitor),
  "￥1,599" and "₹299.00" all read as nothing; ratings in German, French, Spanish and Japanese too. Prices,
  ratings and counts are now read in each marketplace's own format, with the currency the page shows.
- **Half the categories had the wrong name.** Toys, tools, office, garden and movies were called "not served on
  .ca"; Amazon.ca names them toys, hi, office, lawn-garden and dvd. Amazon.de's Electronics is ce-de, so it
  returned nothing. 38 categories are now mapped for each marketplace, each checked live (297 checks).
- **Amazon's refusals passed as results.** A robot check counted as "no results", and an error row was output
  (and charged) in place of a failure. Refusals are now named (robot check, bot check, HTTP 503), tried again
  as a fresh visitor, and a run that got nothing fails with the reason. Nothing is charged for it.
- **Search titles on Amazon.com were rating counts** ("(200536)"). Images were empty for most list rows (a
  second image host wasn't read). Review titles were always empty. Product prices could come from another
  product's widget ($210 for a $15 subscription).
- **Best Sellers Rank, seller and review text were said to be unavailable.** Product pages do show them for
  ordinary products (not for Amazon's own devices): they are now read.

New:

- Change tracking: previous rank, rank change, new on the list, previous price; search position changes; product
  price and rank changes.
- Subcategories by link (any Best Sellers or New Releases page, any marketplace).
- Product pages: list price, stock, seller and shipper, all Best Sellers Ranks, breadcrumbs, bullet points,
  specifications, "bought in past month". Search: organic positions, badges, several keywords per run.
- Max results is shared evenly between lists, keywords and products.
- The proxy setting is followed as given (residential proxies refused, passwords masked).
- Runs resume after a restart without repeating rows. 256 MB by default (peak use was 54-81 MB).

Removed: the `chargeEvent` input (the charged event is fixed) and the error row.

Measured on the platform before release (31 runs from Apify's servers):

- Lists loaded on all ten marketplaces; one Amazon.co.jp run met a robot check on every try and failed, saying
  so; the next one loaded.
- Searches met HTTP 503 often: Amazon.fr succeeded on its fourth try, and Amazon.de, .co.uk, .it and .co.jp
  refused every try. A search page now gets six tries (after 2, 4, 8, 16 and 30 s), and after two keywords in a
  row get nothing on a marketplace, the rest aren't asked, and the run names them.
- AWS WAF's challenge (an HTTP 202 of about 2 KB, `x-amzn-waf-action: challenge`) is named a bot check.
- Amazon.com product pages from the platform sometimes show no featured price ("price not available", no
  featured offer, or unavailable): the price is then empty, never taken from another part of the page.
- Peak memory was 54-109 MB, so runs use 256 MB.

#### 0.1.6 — Stub-response guard

- **Amazon intermittently answers HTTP 200 with a ~4 KB stub** instead of the real
  page (a few hundred KB). `fetch()` treated any 200 as success, so a stub would
  have silently produced **zero rows** for that list. Now responses under
  `MIN_USABLE_HTML` (20 KB) are retried with backoff.
- Measured: 10/10 full pages at 1.2 s spacing, so this is a transient blip rather
  than systematic throttling — but it must not silently empty a run.

#### 0.1.4 — Multi-angle audit fixes

Five issues found by an adversarial audit (static review, failure injection,
input abuse, docs staleness) and fixed:

1. **`inStock` false positives (data correctness).** Availability was decided by
   scanning the whole page for `Currently unavailable|out of stock`. That phrase
   also appears in related-item and other-seller widgets, so genuinely in-stock
   products were reported as out of stock (2 of 5 sampled). Now keyed off
   Amazon's dedicated `<div id="outOfStock">` box — verified 4 True / 1 False on
   a mixed sample.
2. **`inStock` was `None` for out-of-stock items.** The old
   `(not unavailable) if price else None` tied stock state to having a price, so
   an unavailable item with no price returned `None` instead of `False`.
   Unavailable now wins over price.
3. **`maxResults` crashed the Actor on non-numeric input.** `int("abc")` raised
   `ValueError` and killed the run. Now coerced defensively with a warning.
4. **String inputs for list fields iterated per character.** A bare string
   `asins`/`urls`/`listTypes` would be walked character by character, silently
   producing garbage. Now coerced through an `as_list()` guard.
5. **Invalid categories passed through unchecked** and produced a silent empty
   grid. Now validated against the 17 verified categories, with a fallback and a
   warning naming the valid options.

Also in this build:

- **The `proxy` input was non-functional** — it logged a message but never routed
  anything. Apify Proxy is now genuinely wired via `APIFY_PROXY_PASSWORD` /
  `APIFY_PROXY_HOSTNAME` / `APIFY_PROXY_PORT`, plus support for custom
  `proxyUrls`.
- Rows are now only kept when they carry a **title** (a price with no title is
  unreadable to a seller and just inflates the dataset).
- README H1 aligned with the Actor title (congruency).

Audit results otherwise clean: no unknown fields emitted, every emitted field
declared in the dataset schema, no dead schema fields, dataset views reference
real fields only, categories consistent across code / input schema / README,
`exampleRunInput` not the placeholder, parsers survive empty/garbage/truncated
HTML, ranks sequential with no duplicate ASINs, and platform schema validation
correctly rejects bad input with no run created.

#### 0.1.3 — Fix double-counted maxResults guard

- Accepted rows were appended to **both** `rows` and `batch`, and the guard
  `len(rows) + len(batch) >= max_results` counted each row **twice** — every run
  returned exactly half the requested results (60 → 30, 30 → 15). Now guards on
  `len(rows)`.
- Review counts added for list pages (`a-size-small`).
- Boilerplate search titles ("Check each product page…") filtered out.

#### 0.1.1 — Fix input schema

- `items.enum` is not permitted inside an Apify `stringList` editor; valid values
  moved into the description.

#### 0.1.0 — Initial release

- Three modes: `trending` (ranked lists), `products` (ASIN/URL lookup), `search` (keyword).
- Verified extraction for Best Sellers and New Releases: rank, ASIN, title, price,
  rating, review count, image.
- **17 category slugs verified** to return a ranked grid on amazon.ca. Twelve
  obvious candidates (computers, home, toys-and-games, tools, office-products,
  shoes, watches, appliances, camera, wireless, movies-tv, lawngarden) return an
  empty grid on .ca and are deliberately excluded rather than shipped broken.
- **Movers & Shakers excluded**: Amazon.ca returns an empty grid for every
  category tested.
- **BSR / Sold by / Ships from / FBA / offer counts deliberately NOT reported.**
  Verified absent from Amazon.ca's HTML both over plain HTTP and through a full
  headless-browser render. Documented rather than fabricated.
- Batched dataset writes (250 rows per call) so bulk runs do not degrade into
  one write per record.
- Plain impersonated HTTP only — no detection bypass, no anti-detect browser.
