Reverb Music Gear and Sold Price Guide Scraper avatar

Reverb Music Gear and Sold Price Guide Scraper

Pricing

from $1.20 / 1,000 results

Go to Apify Store
Reverb Music Gear and Sold Price Guide Scraper

Reverb Music Gear and Sold Price Guide Scraper

Scrape reverb.com music gear: guitars, amps, synths, pedals, drums and pro audio. Search live listings by brand, category, condition, price, year, region and shipping, or paste links. Uniquely returns the sold Price Guide per gear model: median, low, high and quartile realised prices.

Pricing

from $1.20 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

0

Monthly active users

4 days ago

Last modified

Categories

Share

Pull music gear from Reverb (reverb.com), the marketplace for new, used and vintage guitars, amps, synthesizers, pedals, drums and pro audio. Search live listings with the marketplace's own brand, category, condition, price, year, region, shipping and seller filters, or paste links and let the actor route them. Alongside every listing you also get the Price Guide: what that exact gear model has actually sold for, as a median, a low and high, quartiles, a breakdown per condition, the gap between asking and realised price, the individual recent sales, and a period by period history. Export the dataset as JSON, CSV or Excel, or pull it straight into your app through the API.

Why This Scraper?

  • Realised sale prices, not just asking prices. An asking price tells you what a seller hopes for. This returns what buyers actually paid: median, low, high, 25th and 75th percentile, per condition, with the individual sales behind the numbers and their dates.
  • A deal rating on every live listing. Each listing is positioned against its own model's sold history and labelled below-market, at-market or above-market, with the exact percentage above or below the sold median.
  • Over 60 fields per listing including view and watcher counts, days on market, price drops, seller feedback and rating, seller location, per region shipping rates, return policy, and the canonical model id.
  • Three modes, one actor. Keyword search across live listings, Price Guide lookup by gear model, and paste anything: item links, price guide links, product links, shop links, brand links, marketplace search links, or bare listing ids.
  • Built for recurring monitoring. Incremental mode returns only what changed since the last run, so a daily watch on "1960s Stratocasters under $8,000" returns the new listings and the price drops instead of the same catalogue every day.
  • Filters that actually narrow. Category and price are re-checked against each listing's own data after the search, because the marketplace's own filters can otherwise let off-category or out-of-window rows through.

Use Cases

  • Gear buyers and collectors: check whether an asking price sits below, at, or above what the exact model has actually sold for before making an offer.
  • Dealers and resellers: source stock across brands and categories, and price it against realised sale history instead of sticker prices.
  • Vintage gear researchers: track price trends by condition, year and category over time using the period by period sale history.
  • Marketplace monitoring tools: watch a saved search or a shop and get only new listings, price drops and Price Guide changes on a schedule.
  • Price comparison and alert apps: feed live asking prices plus realised sold prices into your own app, bot or spreadsheet.
  • Market analysts: build datasets of completed sales, ask to sold spreads and per condition pricing for a category of instruments.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
recordType"listing" (also "priceGuide" in Price Guide mode)
listingId"12345678"
title"Sample Vintage-Style Solidbody Guitar"
make / model / year / finish"Sample Brand" / "Model X" / "1965" / "Sunburst"
condition / conditionSlug"Very Good" / "very-good"
price / currency / priceDisplay1200.0 / "USD" / "$1,200"
originalPrice / priceDropPercent1400.0 / 14
categories / rootCategory["Electric Guitars / Solid Body"] / "electric-guitars"
state / inventory / offersEnabled / isAuction"live" / 1 / true / false
shopName / shopSlug / preferredSeller"Sample Music Shop" / "sample-music-shop" / true
sellerLocation / sellerCountryCode"Springfield, United States" / "US"
views / watchers / daysOnMarket240 / 12 / 30 (views and watchers need the item page read on)
freeShipping / shippingRatestrue / [{"regionCode": "US", "price": 0.0}]
photo / photos / photoCountimage URL / list of image URLs / 4
urllink to the listing, model or price guide page
publishedAt / scrapedAt"2026-01-01T00:00:00Z"
guideMedianPrice / priceVsGuidePercent / dealRating1350.0 / -11.11 / "below-market" (needs the sold Price Guide on)
soldPriceMedian / soldPriceLow / soldPriceHigh1350.0 / 900.0 / 2200.0 (inside priceGuide on listings)
byCondition / recentSales / priceHistoryper-condition breakdown / individual sales / monthly averages, as arrays
changeType / firstSeenAt / lastSeenAt"NEW" / "2026-01-01T00:00:00Z" / "2026-01-01T00:00:00Z" (incremental mode only)

Price Guide mode records (recordType priceGuide) are a gear MODEL rather than one listing: productId, soldSalesTotal, soldSampleSize, soldPriceP25, soldPriceP75, soldPriceAverage, askPriceAverage, askToSoldDiscountPercent, firstSaleDate, lastSaleDate, usedListings, newListings, usedLowPrice, newLowPrice, productRating and productReviewCount.

soldPriceMedian is the number to compare an asking price against, and soldPriceP25 / soldPriceP75 bracket the normal trading range that dealRating is judged from. A model with fewer than five recorded sales gets its live-market snapshot (usedListings, newListings, usedLowPrice, newLowPrice) but no dealRating, left empty rather than guessed on a thin sample. A sale recorded in a currency other than the reported one is excluded from the statistics rather than mixed in, and the count of excluded sales is reported as mixedCurrencySalesSkipped.

How to Use

  1. Pick a mode: search (keyword search across live listings, with filters), price-guide (look up gear models and their realised sold-price statistics), or url (paste links).
  2. Add keywords or links, and for search and Price Guide modes narrow with the brand, category, condition, price, year, region and shipping filters (URL mode ignores them, the link carries its own).
  3. Turn on the sold Price Guide and, if you also want each listing's own item page (views, watchers, seller location, policies and videos), turn that on too. Each is a per-result surcharge, so a lean run can leave both off.
  4. Set Max results, click Start, then read the dataset as JSON, CSV or Excel, through the API, or via the MCP connector.

Search live listings with filters:

{
"mode": "search",
"queries": ["Stratocaster"],
"category": "electric-guitars",
"conditions": ["excellent", "very-good"],
"minPrice": 500,
"maxPrice": 3000,
"includeSoldPriceGuide": true,
"maxItems": 20
}

Look up what gear models actually sell for:

{
"mode": "price-guide",
"queries": ["Moog Subsequent 37", "Shure SM57"],
"includeSoldPriceGuide": true,
"maxItems": 20
}

Paste links of any supported kind:

{
"mode": "url",
"urls": [
"https://reverb.com/item/00000001-sample-listing",
"https://reverb.com/price-guide/sample-brand-model",
"https://reverb.com/shop/sample-music-shop",
"https://reverb.com/marketplace?query=Gibson%20Les%20Paul&condition=used"
],
"includeSoldPriceGuide": true,
"maxItems": 100
}

Watch a search daily and get only the changes:

{
"mode": "search",
"queries": ["1960s Stratocaster"],
"maxPrice": 8000,
"incrementalMode": true,
"stateKey": "vintage-strat-watch",
"maxItems": 0
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/reverb-scraper").call(run_input={
"mode": "search",
"queries": ["Stratocaster"],
"maxItems": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item.get("price"), item.get("dealRating"))

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/reverb-scraper').call({
mode: 'search',
queries: ['Stratocaster'],
maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Filters that narrow twice

Category and price are applied both upstream (so the walk itself stays narrow) and again against each returned listing's own category and its own US dollar price, because the marketplace's own matching can otherwise let off-category or out-of-window rows through, sometimes a large share of a page. The walk for a keyword stops reading new pages once it has read enough candidate listings to fill that keyword's share of maxItems, and the re-check runs after that. So a heavily filtered run can return fewer rows than maxItems asks for even when later pages still hold matching listings. Raising maxItems makes the walk read further.

In search and Price Guide modes each keyword gets its own share of maxItems, split evenly, so the first keyword of a multi-keyword run cannot silently use up the whole cap. A share a keyword does not fill (because it has fewer matches) is not handed on to the other keywords. In URL mode the pasted item and model links are read first, then each pasted search, shop or brand link in order takes whatever is left of maxItems, so an early search link can use up the rest of the cap on its own.

Results are read 50 at a time (one page), so the walk for one keyword can read up to a full page of candidates before trimming to that keyword's own share. A listing read past the share is already counted as seen for duplicate detection even though it was never returned. When two keywords in the same run overlap (close synonyms, or one a substring of the other), a later keyword skips those listings, so it can return fewer matches than it would alone, or none at all, and the run can finish below maxItems. Run overlapping keywords as separate runs if you need every match from each one.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run or dataset id and the actor skips everything already collected there, so you don't pay twice.
  • Incremental mode (incrementalMode) is for running this same search again and again (for example daily) and getting only what changed. Each result is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), REAPPEARED, or EXPIRED (only after a run that scanned the whole tracked search, and only with emitExpired). stateKey names or shares the stored state; leave it empty to let the actor derive one from the mode, keywords, links and filters.
  • EXPIRED rows are not limited by Max results. They are computed from whatever is left in the tracked baseline once a complete scan proves it is gone, and Max results only governs the live collection in that same run. A state key tracking a large catalogue that mostly disappeared between runs (for example after narrowing the filters) can return far more EXPIRED rows in one run than Max results was set to. If you need a hard ceiling on a single run's total output, keep emitExpired off, or use a narrower, more stable tracked search.
  • Incremental mode with a Max results cap counts unchanged listings while walking. The walk for a keyword stops reading new pages once it has read that keyword's share of maxItems in listings not already seen this run, whether or not they turn out to be unchanged. If the first page is all unchanged, the run can stop there and report nothing changed even though new listings sit on a later page. For scheduled monitoring, set maxItems to 0 (as in the example above), or at least sort by newest so new listings come first.
  • Seeding incremental state from a resumed run is a one-off with a catch. Combining resumeFromRunId with incrementalMode on a state key with no saved state records every result of the resumed run as already known, but without its details. The next incremental run therefore returns each of those results once as UPDATED (and bills it), with every field listed in changedFields. From the run after that they are classified normally.
  • A run that the platform restarts part way through (for example when it moves the run to another server) picks up again at the keyword or link it was working on. That keyword or link starts from its first page again, so rows it had already returned can be returned (and billed) a second time, and the run's total can go over maxItems. In incremental mode, rows returned before the restart for earlier keywords are not recorded in the saved state, so the next run reports them as NEW again.

Send results into your apps (MCP connectors)

Optionally pipe results into Notion, Linear, Airtable or Apify via MCP connectors, using the Export to your apps (MCP connectors, optional) section of the input. Authorize a connector under Apify, Settings, API and Integrations, then select it here.

  • mcpConnectors selects the connectors this run exports into.
  • notionParentPageUrl is the Notion page under which one page per item is created. It is required for the Notion export and ignored by every other connector.
  • maxNotifyListings caps how many items are written to each connector.

Each connector receives a condensed, human readable summary per item: a title plus the key fields flattened to plain text, with nested objects collapsed to their main value and long lists trimmed. The complete record, including the whole priceGuide block, always stays in the Apify dataset. The export is a side channel: it never changes the dataset output, and a connector error is logged as a warning while the run still succeeds.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch, price-guide, or url.
queriesarray["Fender Stratocaster"]Keywords, read in search and Price Guide modes. Each is searched separately and gets its own share of the item cap.
urlsarraysampleReverb links or bare listing ids, read in URL mode. Filters below are ignored in this mode.
makestring(none)Brand. Applies to search and Price Guide modes.
categorystring(any)One of the 14 top-level categories. Applies to search and Price Guide modes.
minYearinteger(none)Earliest year. Applies to search and Price Guide modes.
maxYearinteger(none)Latest year. Applies to search and Price Guide modes.
conditionsarray[]One or more of new, b-stock, used, mint, excellent, very-good, good, fair, poor, non-functioning. Search mode only.
minPriceinteger(none)Minimum price in US dollars. Search mode only.
maxPriceinteger(none)Maximum price in US dollars. Search mode only.
itemRegionstring(any)Seller country. Search mode only.
shipsTostring(anywhere)Country the seller ships to. Search mode only.
shopSlugstring(none)One seller, given as the handle in the shop address. Search mode only.
handmadeOnlybooleanfalseHandmade or custom built gear only. Search mode only.
freeShippingOnlybooleanfalseOnly listings that ship free. Search mode only.
preferredSellersOnlybooleanfalsePreferred sellers only. Search mode only.
sortBystringrelevancerelevance, price-asc, price-desc, or newest. Search mode only.
includeSoldPriceGuidebooleantrueAttach the realised sale statistics, and score each live listing against them.
fetchDetailsbooleanfalseRead each listing's own item page for views, watchers, seller location, policies and videos.
maxItemsinteger20Maximum number of results returned across the whole run. 0 for unlimited.
maxPagesinteger0Maximum result pages walked per keyword or link, at 50 results a page. 0 for no page limit.
resumeFromRunIdstring(none)Continue one interrupted run without returning, or charging for, results already collected there.
incrementalModebooleanfalseTurn this on for daily or recurring monitoring: return only what changed since the last run of this search.
stateKeystring(none)Name a monitoring campaign, or share state across differently configured runs. Derived automatically when empty.
emitUnchangedbooleanfalseAlso return (and bill) results that have not changed since the last run.
emitExpiredbooleanfalseAlso return (and bill) results that were present before and are no longer found.
proxyobjectApify ProxyConnection settings. Leave the default selected unless a run reports refused requests.
mcpConnectorsarray(none)Optional: send a summary of each result to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"recordType": "listing",
"listingId": "00000001",
"sku": "REF-0001",
"slug": "sample-brand-model-1965-sunburst",
"url": "https://reverb.com/item/00000001-sample-brand-model-1965-sunburst",
"comparisonShoppingPageId": "000000",
"title": "Sample Brand Model 1965 Sunburst",
"make": "Sample Brand",
"brandSlug": "sample-brand",
"model": "Model X",
"year": "1965",
"finish": "Sunburst",
"rootCategory": "electric-guitars",
"categories": ["Electric Guitars / Solid Body"],
"condition": "Very Good",
"conditionSlug": "very-good",
"price": 1200.0,
"currency": "USD",
"priceDisplay": "$1,200",
"originalPrice": 1400.0,
"priceDropPercent": 14,
"state": "live",
"inventory": 1,
"offersEnabled": true,
"offerCount": 0,
"isAuction": false,
"freeShipping": true,
"freeExpeditedShipping": false,
"shippingRates": [{ "regionCode": "US", "price": 0.0, "currency": "USD" }],
"shopName": "Sample Music Shop",
"shopSlug": "sample-music-shop",
"preferredSeller": true,
"sellerFeedbackCount": 120,
"sellerRatingPercentage": 100.0,
"sellerLocation": "Springfield, United States",
"sellerCountryCode": "US",
"views": 240,
"watchers": 12,
"daysOnMarket": 30,
"publishedAt": "2026-01-01T00:00:00Z",
"scrapedAt": "2026-01-01T00:00:00Z",
"guideMedianPrice": 1350.0,
"priceVsGuidePercent": -11.11,
"dealRating": "below-market",
"priceGuide": {
"soldSalesTotal": 140,
"soldSampleSize": 60,
"currency": "USD",
"soldPriceLow": 900.0,
"soldPriceP25": 1100.0,
"soldPriceMedian": 1350.0,
"soldPriceP75": 1600.0,
"soldPriceHigh": 2200.0,
"soldPriceAverage": 1380.0,
"askPriceAverage": 1490.0,
"askToSoldDiscountPercent": 7.4,
"firstSaleDate": "2024-03-01",
"lastSaleDate": "2026-01-01",
"byCondition": [
{ "condition": "Excellent", "salesCount": 22, "lowPrice": 1200.0, "medianPrice": 1450.0, "highPrice": 1700.0 }
],
"recentSales": [
{ "date": "2026-01-01", "condition": "Excellent", "askPrice": 1500.0, "soldPrice": 1425.0, "currency": "USD" }
],
"priceHistory": [
{ "periodStart": "2025-12-01", "averageAskPrice": 1490.0, "averageSoldPrice": 1380.0 }
],
"liveMarket": { "usedListings": 34, "newListings": 6, "usedLowPrice": 900.0, "newLowPrice": 1899.0 },
"mixedCurrencySalesSkipped": 0
}
}

Plan Requirement

The default connection works out of the box on every plan. If a run reports refused requests, switch to the residential connection group under Connection, which is billed by traffic and costs more, so keep it off unless the default is being refused.

FAQ

How much does it cost?

You pay per result returned, with the sold Price Guide and each listing's own item page billed only when you switch them on, once per result they actually add data to. The Pricing tab shows the current rates. Use Max results to cap the cost of any run.

This actor collects only publicly available marketplace data. You are responsible for how you use it: follow Reverb's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing content, photos and seller information may carry rights belonging to the seller or the marketplace.

Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared results by default, and unchanged ones are not billed unless you turn emitUnchanged on. Leave Max results at 0 for monitoring runs so the walk is not cut short by unchanged listings.

Why did I get fewer results than Max results asked for?

A few reasons, all described under How to Use above. The category and price filters are re-checked against each listing's own data after the walk has already stopped reading pages, so a heavily filtered run can return fewer than maxItems even when later pages hold more matches. Each keyword only gets its own share of the cap, and an unused share is not passed on. Keywords that overlap in one run can take matches away from each other. In incremental mode, unchanged listings are suppressed but still count toward the walk's stop point. Raise maxItems, broaden the filters, or run overlapping keywords separately.

Why did incremental mode return more EXPIRED rows than Max results?

emitExpired rows come from comparing the whole tracked baseline against what a complete scan found this run, and that comparison is not capped by maxItems, only the live collection is. A state key watching a large catalogue that shrank a lot since the last run (for example after narrowing the filters) can return many more EXPIRED rows in one run than maxItems was set to. Keep emitExpired off if you need a hard ceiling on a single run's output.

Why did my run fail instead of returning an empty dataset?

If every request was refused, the run stops with a clear message so "nothing matched" is never confused with "nothing could be read". Run it again in a few minutes, or switch the connection if it keeps happening.

What is the difference between Resume and Incremental mode?

Resume (resumeFromRunId) continues one specific interrupted run using its run or dataset id. Incremental mode remembers state itself, keyed on the search, and is for running the same search again and again on a schedule. They can be combined once, to seed a brand-new monitoring campaign's baseline from an existing run, but not against a state key that already has saved state. After such a seed, the next incremental run returns every seeded result once as UPDATED (billed), because the seed records which results exist but not their details.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

๐Ÿ”— Want more e-commerce data?

Pair this actor with these related scrapers from the same team:

โšฝ Whatnot Scraper
Scrape Whatnot live and upcoming shows, queued items and lots, and seller profiles...
๐Ÿ›’ Depop Scraper
From $1/1K. Scrape Depop search results, listings, shops, and reviews to JSON, CSV, or...
๐Ÿท๏ธ Vinted.fr
Scrape Vinted.fr, France's C2C second-hand fashion marketplace: search with...
๐Ÿท๏ธ Chrono24 Scraper
Scrape Chrono24 luxury watch listings by keyword, filters or URL. Extract 50+ fields...
๐Ÿ›’ Mercari Japan Scraper
From $0.80/1K. Scrape Mercari Japan listings, sellers and reviews at scale. Extract...
๐Ÿ›’ OfferUp Scraper
Scrape OfferUp listings by keyword, location and radius. Returns 40+ fields per item...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support

  • ๐Ÿž Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • ๐Ÿ› ๏ธ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.