Reverb Listings Scraper
Pricing
from $1.75 / 1,000 results
Reverb Listings Scraper
Music gear listings from Reverb: price, condition, make, model, year, shop and shipping. Every run proves its filters were applied -- Reverb accepts an unrecognised filter value, ignores it, and answers with the whole 794,000-listing catalogue instead of an error.
Pricing
from $1.75 / 1,000 results
Rating
0.0
(0)
Developer
Ibnu Adzim
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Music gear from Reverb — guitars, amps, pedals, synths, drums, pro audio — with price and currency, condition, make, model, year, the shop selling it, and shipping rates per region.
Built on Reverb's own public REST API. HTTP only, no browser.
What it is for
- Price research on used gear — what a 1979 Stratocaster actually sells for, by condition, by year, by region.
- Inventory monitoring — new listings for a make or model, newest first.
- Market sizing — how many listings exist in a category, and at what prices.
- Dealer tracking — every row carries the shop, whether it is a preferred seller, and its shipping rates.
Input
| field | what it does |
|---|---|
queries | Search terms: stratocaster, les paul, moog, shure sm57. |
categorySlugs | electric-guitars, effects-and-pedals, amps, drums-and-percussion… |
conditions | new, used, b-stock, mint, excellent, very-good, good, fair, poor, non-functioning. |
makes | Fender, Gibson, Boss, Shure. |
priceMin/priceMax, yearMin/yearMax | Price and year of manufacture. |
shipsTo, currency | Two-letter country, three-letter currency. |
sortBy | Newest, oldest, price low→high, price high→low. |
maxItems, perPage, maxConcurrency | Limits and pacing. |
Give both search terms and categories and every term is run inside every category.
Five things about this data worth knowing before you trust a run
1. A filter Reverb does not recognise is ignored, not rejected
Against guitar, whose unfiltered total is ~794,000:
| filter | listings reported |
|---|---|
condition=used | 257,022 — real |
condition=zzqq | 794,220 — silently unfiltered |
condition=brand-new | 794,217 — silently unfiltered |
make=Fender | 82,934 — real |
make=ZzqqNotAMake | 794,222 — silently unfiltered |
ships_to=ZZ | 794,220 — silently unfiltered |
Only a bad currency is refused out loud. brand-new is the nastiest of
these: it is exactly what the listings themselves display, and the slug that
actually filters is new.
So every run spends one extra request on the same query without the
filters, and stops if the filters did not move the result count. The summary
reports baselineTotal, filtersHeld and totalMovedShare so you can see the
arithmetic.
2. Three numbers describe the result set and none is the limit
total 794,218 the real match count — honesttotal_pages 50 a CONSTANT. It is 50 at perPage 1, 5, 20 and 50.actual limit 20,000 rows, as an OFFSET, not a page number
Confirmed four ways — the break is always at offset > 20,000, never at a page
number. A scraper that trusts total_pages stops after 50 pages; one that
computes total / perPage asks for 15,884 pages and hits an HTTP 400 partway.
And in practice you get far less than 20,000, because deep paging re-serves
listings you have already seen. A measured walk of 112 pages returned 3,837
unique listings and 1,763 duplicates. Those duplicates are dropped and
counted in duplicateRowsDropped. To go wider, slice by price band, category or
make rather than paging.
3. With some search terms, the count is filtered by category and the rows are not
This is the subtle one. Searching guitar inside electric-guitars:
totalsays 218,938 — the filtered number- Reverb's own echo says
"guitar" in Electric Guitars - and 18 of 20 returned listings are acoustic guitars
Measured across ten search terms against the same category, only two misbehave, and both are terms that name a neighbouring category:
| search term | rows actually in the category |
|---|---|
guitar | 2 / 20 |
acoustic | 6 / 20 |
| stratocaster, les paul, telecaster, amp, pedal, fuzz, ibanez | 20 / 20 |
The total cannot detect this — it looks perfect in exactly this case. Only the
rows can. Every run with a category therefore reports categoryHeldShare, and a
run where most rows are from elsewhere is an error, not a page of the wrong
department.
4. Sorting only works in a form nobody would guess
sort=price|desc works. sort=price_desc — the spelling every other API uses —
is accepted, ignored, and returns the default order with HTTP 200. You pick from
an enum and this Actor sends the working form, then checks the returned order
really is sorted and reports sortVerified.
One wrinkle behind that check: Reverb sorts on the listing's native amount
and shows you a converted one. A price|asc page came back
0.99 USD, 1.00 USD, …, 1.50 (native CAD), 1.48 (native AUD)5. condition filters on a tier the rows do not report
condition=used narrows 794,218 → 257,022 correctly, and then not one
returned row says "Used" — they say Excellent, Very Good, Good, Fair. used
is a meta-condition covering the grades. So per-row verification is applied only
to make, whose vocabulary does match the rows (and even there, matched as a
prefix: a Fender search returns rows labelled both Fender and
Fender Guitars).
Output
Three record types in one dataset, told apart by recordType:
LISTING—title,make,model,year,finish,price+currency+buyerPrice(tax-inclusive where it applies) +listingCurrency,condition+conditionSlug,categories,shopName+preferredSeller,shipping(cheapest rate and region),photos,listingUrl.QUERY_SUMMARY—matchesReported,totalPagesReported(Reverb's constant 50, shown so the difference is visible),baselineTotal,filtersHeld,totalMovedShare,makeHeldShare,categoryHeldShare,sortVerified,ceilingHit,duplicateRowsDropped.ERROR— one row naming what went wrong, instead of a silent empty.
Technical notes
- HTTP-only,
curl_cffiwithchrome124. No WAF, no challenge. Accept-Version: 3.0is mandatory — without it every call is a 400. Version 2.0 is deprecated, and its error message came back in Italian from a non-US exit IP: Reverb localises error strings by geography, so no code here matches on error text, only on status and structure.- HTTP 400 is an answer, not a fault past the offset ceiling, so it is never retried.
- Proxy is optional and off by default. Prices follow the
currencyparameter, not the exit IP, so leave the pool unpinned if you enable it. - robots.txt was read per origin, comments included. No AI-bot group, no
blanket disallow; the four
/api/rules cover account data and ad surfaces, none of which this Actor reads.
Known limits
- No price guide.
/api/priceguidereturns 403 without authentication, so sold-price history is out of reach. - ~4,000 unique listings per query in practice (see above). Slice to go wider.
perPageis clamped at 50 by Reverb; larger values silently return 50.- 13 category slugs in Reverb's tree are not unique (
cables,delay,archtop,left-handed…). An ambiguous bare slug is refused with the qualifiedroot/slugalternatives rather than resolved to whichever the parser saw last.