Reverb Listings Scraper avatar

Reverb Listings Scraper

Pricing

from $1.75 / 1,000 results

Go to Apify Store
Reverb Listings Scraper

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

Ibnu Adzim

Maintained by Community

Actor 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

fieldwhat it does
queriesSearch terms: stratocaster, les paul, moog, shure sm57.
categorySlugselectric-guitars, effects-and-pedals, amps, drums-and-percussion…
conditionsnew, used, b-stock, mint, excellent, very-good, good, fair, poor, non-functioning.
makesFender, Gibson, Boss, Shure.
priceMin/priceMax, yearMin/yearMaxPrice and year of manufacture.
shipsTo, currencyTwo-letter country, three-letter currency.
sortByNewest, oldest, price low→high, price high→low.
maxItems, perPage, maxConcurrencyLimits 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:

filterlistings reported
condition=used257,022 — real
condition=zzqq794,220 — silently unfiltered
condition=brand-new794,217 — silently unfiltered
make=Fender82,934 — real
make=ZzqqNotAMake794,222 — silently unfiltered
ships_to=ZZ794,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 — honest
total_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:

  • total says 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 termrows actually in the category
guitar2 / 20
acoustic6 / 20
stratocaster, les paul, telecaster, amp, pedal, fuzz, ibanez20 / 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)
— three inversions in twenty rows, every one at a currency boundary. Verification is therefore scoped to rows whose listing currency is the currency shown.

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_cffi with chrome124. No WAF, no challenge.
  • Accept-Version: 3.0 is 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 currency parameter, 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/priceguide returns 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.
  • perPage is 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 qualified root/slug alternatives rather than resolved to whichever the parser saw last.