Skip to content
amz

v0.3.0

The version that made the tool honest: no cookies, no user agent rotation, robots.txt enforced at request time, and every record says where it came from and what it could not find.

v0.2.1 sent rotating browser user agents, loaded cookies from a file, ignored robots.txt, and pointed four commands at pages that redirect to a login. It got blocked, and it deserved to.

This release deletes all of that, points every command at a surface that answers a logged out reader, and makes every record say where it came from and what it could not find.

Breaking changes

No command is removed. Three change what they read, one loses a flag, and the record shape changes.

v0.2.1 v0.3.0
amz reviews reads /product-reviews/, which redirects to a login reads the reviews and the histogram embedded in the detail page, and says in missed that the corpus needs a login
amz qa reads /ask/questions/, which redirects to a login reads the answered question count and any inline pairs, and says the rest needs a login
amz offers reads /gp/offer-listing/, which is disallowed and redirects reads the buy box from the detail page and states the count behind it. Needs no flag
amz product returns 38 fields returns everything the 288 feature regions carry
--cookies <file> removed. The code that sent a Cookie header is deleted
--workers <n> removed. One connection, paced
rotating browser user agents one honest user agent naming the tool and its repo
flat records records carry an envelope, so every JSON key moves down one level unless --flat
amz db query needs a duckdb binary pure Go SQLite, nothing to install
exit 5 for everything unusual 5 CAPTCHA, 6 challenge, 7 needs --no-robots, 8 robots unfetchable, 9 needs a login

The change most people will notice is that amz reviews returns a handful of reviews instead of failing, so the message has to be a good one when you wanted all of them:

$ amz reviews B075F5X8BR
# 13 reviews on stdout, then on stderr:
amz: 13 of 21095. amazon requires a sign-in for the review corpus, and the detail page carries the histogram and the reviews medley only. the total is the ratings count, which is the largest number the page states
amz:   /product-reviews/ is not readable without a session
amz:   /portal/customer-reviews/ is not readable without a session
amz: run `amz why reviews` for the detail

Thirteen reviews and an honest sentence beats zero reviews and wrong advice.

Every record says where it came from

A record now carries an envelope beside its fields. It names the responses the record was read from, the region each field came out of (via), which rung of the extraction ladder answered (level), what was looked for and not found (missed), and what is on the page that nothing reads yet (unread).

That last part is the design. If a field is missing and nothing in missed names it, amz read the place that field lives and there was nothing there. Absence is an answer rather than a gap.

robots.txt is asked, not assumed

The marketplace's live robots.txt is fetched, parsed and enforced before every request, cached for 24 hours with the time it was fetched. Nothing about it is compiled in, and amz robots check <url> prints the rule that decided any URL.

--no-robots is an explicit, loud, per-run override that prints every rule it breaks and raises the pace floor to 5s. There is no no_robots config key and no AMZ_NO_ROBOTS environment variable, and there are tests asserting neither ever appears. A stop signal you can turn off in a file you forgot about is not a stop signal.

Getting past 306 results

Amazon serves at most 306 results over 20 pages for any query, whatever total it advertises. amz search --all partitions the query on a refinement group, runs one search per value, and unions the cells on ASIN.

Measured on 2026-08-18, amz search "usb-c hub" --all partitioned on Brands into 68 cells and returned 1,508 unique results. It reports the cells that still hit the ceiling and the ones Amazon served unfiltered, so the holes in the union are named rather than papered over.

The refinement vocabulary is read, not compiled in

Only six refinement codes mean the same thing on every search. Everything else is per query, so the sidebar is the source: amz refine <query> prints every group a query offers with its code, label, scope and values. A refinement Amazon takes and then does not apply is an error rather than an unfiltered result set wearing a filter's label.

A local store with nothing to install

SQLite is compiled into the binary as pure Go. crawl, db, query, find, lookup, graph, series and export all work on a machine with nothing on it but this binary.

New commands

Command What it does
why [topic] why something returns less than you expected, with the measurement and the date
surfaces every Amazon surface amz knows, what robots says about it, when it was measured
extraction the four rung ladder, and what is on a page that nothing reads yet
verify today's read against the golden captures, so drift is caught
refine the refinement vocabulary a query offers
variants the variation matrix, one row per sibling
tree walk the browse node graph outward
find, lookup, graph, series, query read the local store with no network
serve, mcp the read commands over HTTP and as Model Context Protocol
doctor check the client is honest, the network works and the store is readable
agent-map Amazon's own description of a page, verbatim

Fixes

amz brand <name> works with a bare name. Amazon puts a storefront at /stores/<name>/page/<uuid> and nothing derives that uuid from the name, so /stores/anker is a 404 and always was. A bare name is now resolved through the byline link on a product the brand sells.

The brand is also read off premiumBylineInfo, which is where Amazon puts it for a premium brand while leaving bylineInfo on the page and empty. Until now every premium brand, which is most of the ones anybody searches for by name, came back with a null brand and a null brand URL.

One cell of a partitioned search that Amazon serves unfiltered no longer discards the whole union. It is recorded, named in the summary, and the other cells are still read.

Migrating

--flat emits the v0.2.1 product record for one more version and prints a deprecation note. It goes away in v0.4.0. The envelope travels with it, because provenance is not a projection.

--cookies and --workers are gone with no replacement. If you were using cookies to reach the review corpus or the all-offers panel, read amz why reviews and amz why offers: both now return what the public page carries and say what is behind the login and why. If you were using --workers to go faster, that is the reason the tool got blocked. --rate only goes slower.

The full list of renamed fields is in the changelog.