I run a visa agency in Bali. The part of my week that has nothing to do with visas goes into scrapers on Apify, and one of them reads Amazon's Best Sellers and New Releases lists — the ranked top 100 of any category on 21 marketplaces, over plain HTTP, no browser and no login.
That Actor health-checks itself every night, which means I did not have to run an experiment to get a panel: 40 runs of one list — Best Sellers in Electronics on amazon.com, 50 rows a time — spread over 24 distinct days between 12 October and 9 November, 1,609 product rows. Some of those days carry two or three runs minutes apart, because a failed check gets retried. Those accidental duplicates turned out to be the most interesting rows in the file.
Rank is a cache. Ratings counts are not
Amazon's help pages say the Best Sellers lists are "updated hourly". I sorted my 40 runs by time, took every consecutive pair, and asked three questions of the ASINs present in both: did rank change, did price change, did the ratings count change.
| gap between runs | pairs | pairs with zero rank changes | median ranks moved (of ~26) |
|---|---|---|---|
| under 1 h | 10 | 10 | 0 |
| 3.3 h and 4.2 h | 2 | 1 | 1 |
| 6.7–8.5 h | 3 | 0 | 12 |
| over 12 h | 24 | 0 | 15 |
Eleven of the twelve pairs taken less than 4.3 hours apart came back with the identical ranking, position by position. Every one of the 27 pairs taken more than 6.6 hours apart had 11 to 18 of about 26 shared products in a different slot. So for this category the practical refresh is somewhere in the 4–7 hour range, not hourly, and scheduling a rank tracker more often than every six hours buys you nothing but rows.
Except that the rest of the card is not frozen with it. In the pair 3.3 hours apart, zero ranks moved and 9 of 27 ratings counts did. In the 4.2-hour pair, 2 ranks moved and 14 ratings counts did. One pair four minutes apart has an identical ranking, identical ratings counts, and one changed price.
That is a useful split to know before you design a table: rank and reviewsCount on the same row are not snapshots of the same moment. The ranking comes out of a periodically recomputed list; the price and the ratings count are rendered from whatever the catalogue says when the page is built.
The #1 Electronics product on amazon.com is not a product
Nine ASINs held a top-27 slot on all 24 days. Fifty-nine distinct ASINs passed through the top 27 in total, nine of them on exactly one day, and the median day brought two new entrants.
Rank 1 never moved once in 24 days — and it is B08JHCVHTY, "blink plus plan with monthly auto-renewal", $11.99. A camera subscription. It was #1 again in a control run I did today while writing this. If your pipeline assumes the top of a department is hardware, the first row will break it.
Rank does not rank sales velocity
Thirty ratings a day is not sales, but it is the only velocity signal a list card carries. For the 28 ASINs I had at least ten days and a two-week span for, I divided the ratings gained by the days elapsed and compared it with the product's median rank. Spearman correlation: −0.364. Weak, and in places inverted:
| median rank | ratings/day | product |
|---|---|---|
| 17.5 | 109.9 | Soundcore Q20i headphones |
| 17.0 | 91.6 | Soundcore P30i earbuds |
| 2.0 | 41.5 | Apple EarPods USB-C |
| 1.0 | 29.8 | blink plus plan |
| 6.0 | 13.9 | Apple AirPods 5 (184 → 574 ratings) |
The product at median rank 17.5 collected 3.7x more ratings per day than the one that never left #1. Cheap accessories get reviewed at a different rate than Apple hardware, and a subscription barely gets reviewed at all — so review velocity and rank are measuring two different things and neither one is units sold. If you need units, this list cannot give them to you; nothing public can.
Ratings counts go down
Across 1,435 same-ASIN comparisons in the panel, the ratings count fell 34 times. Thirty-two of those are drops of 1 to 10 — Amazon pruning reviews, which is normal and invisible at any sane rounding.
The other two belong to one ASIN, and they are not noise. B08TVLYB3Q, a 400-pack of cable ties:
2026-10-27 00:08 24,722
2026-10-27 20:05 24,008 <-- 714 lower
2026-10-30 00:17 24,030
2026-10-31 00:16 24,774 <-- back on the high series
2026-10-31 20:12 24,786
2026-11-01 20:11 24,061 <-- and back to the low one
2026-11-09 20:12 24,161
Two parallel totals about 715 apart, each drifting upward on its own, and the page hands you one or the other. Same ASIN, same title, same 4.6 stars, same $6.99. This is what a review-aggregation split across a variant family looks like from the outside. If you are diffing day over day, a jump of that size is not a scrape error and not a review purge — clamp it or keep both series, but do not average them.
The price field, and a bug I shipped a fix for today
Here is what a Best Sellers card actually contains. I fetched Kitchen & Dining from my own server and checked the markup of all twelve cards the Actor returned: none of the twelve carry Amazon's own price element. All twelve print "N offers from" with the price in hidden text, and that hidden text has no decimal separator:
<span class="a-color-base">6 offers from
<span class="a-price"><span class="a-offscreen">$2997</span>
<span aria-hidden="true">$<span class="a-price-whole">29</span>
<span class="a-price-fraction">97</span></span></span>
$2997 is $29.97. Yesterday's run of the same list put ten of nineteen prices in the dataset as $2849, $1839, $1000, $799. Today's build reads the visible whole and fraction spans when the hidden text has no separator, and the same list comes back with $29.99, $19.99, $3.59, $9.97 — zero decimal-less prices. Build 0.1.28, verified against the live markup before the tag moved.
Two honest leftovers from that pass:
One row still comes back with price: null. The Stanley tumbler at rank 10 returned no price in three runs today, while the same card fetched from my own machine four minutes earlier carried the 6 offers from $2997 block. The price block in that card is session-dependent, and when the run does not get it there is nothing to parse. price: null is a state you have to handle, not a failure.
The "offers from" number is not the price. Comparing my fetch with the run 4.5 minutes later, 5 of 12 of those hidden prices agreed and 6 disagreed — $10.91 against $12.31, $8.99 against $9.99. That is the cheapest of N third-party offers resolved per session, not a fixed catalogue price. For a product with one seller it is the price; for a 22-offer listing it is a quote.
Calling it
{
"categories": ["electronics"],
"marketplace": "US",
"listType": "bestsellers",
"maxItemsPerCategory": 10
}
A real row from today's control run:
{
"type": "product", "rank": 2, "asin": "B0DCH8VDXF",
"title": "Apple EarPods Headphones with USB-C Plug, Wired Ear Buds with Built-in Remote...",
"url": "https://www.amazon.com/dp/B0DCH8VDXF",
"price": 19, "priceMax": null, "currency": "USD", "priceText": "$19.00",
"rating": 4.5, "reviewsCount": 20049,
"listType": "bestsellers", "category": "Electronics",
"categoryUrl": "https://www.amazon.com/gp/bestsellers/electronics",
"marketplace": "US", "domain": "amazon.com", "depth": 0, "page": 1,
"scrapedAt": "2026-11-10T05:25:33.682Z"
}
From Python, run and diff against yesterday in one call:
import requests
rows = requests.post(
"https://api.apify.com/v2/acts/lergassy~amazon-bestsellers-scraper/run-sync-get-dataset-items",
params={"token": "apify_api_..."},
json={"categories": ["Home & Kitchen", "Electronics > Headphones"],
"marketplace": "US", "listType": "bestsellers", "maxItemsPerCategory": 50},
timeout=600,
).json()
items = [r for r in rows if r.get("type") == "product"]
by_rank = {(r["category"], r["rank"]): r["asin"] for r in items}
The Actor is Amazon Best Sellers & New Releases Scraper. Median run time across those 40 panel runs was 4.5 seconds (2.3 to 9.6) for 50 rows, because the first 30 cards are in the HTML and ranks 31–50 come from the same endpoint the page itself calls while you scroll. A 10-row run on my test account billed $0.018 and said so in a free summary row.
When it is the wrong tool. If you need units sold, stock or a seller name, a list card has none of them. Movers & Shakers, Most Wished For and Gift Ideas are not usable at all right now — Amazon answers a signed-out visitor with "Sorry, there are no movers and shakers available in this category", and the Actor passes that sentence through as a free error row rather than pretending the category is empty. A list is capped at 100 ranks, delivered as two pages of 50; for more you turn on subcategories, and then you must dedupe, because Apple's EarPods sat at rank 2 in Electronics and rank 3 in Electronics Accessories & Supplies in the same run. And if you are writing your own: do not trust the ranking you get twice in an hour to mean the list changed — mine did not change once in eleven tries.
Top comments (0)