Discogs Scraper - Vinyl Records, Prices & Price Stats
Pricing
from $1.20 / 1,000 records
Discogs Scraper - Vinyl Records, Prices & Price Stats
Scrape the Discogs catalogue by keyword, filter or link: releases, masters, artists and labels with tracklists, credits, matrix numbers, images and videos. Cross-pressing price statistics: lowest, median, highest and average asking price across an album's pressings, plus want/have demand.
Pricing
from $1.20 / 1,000 records
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Categories
Share
Discogs Scraper: Records, Marketplace Prices & Price Statistics
Discogs Scraper turns the Discogs catalogue and marketplace into structured data. Search by keyword or filter, or paste release, master, artist and label links, and get releases, masters, artists and labels with tracklists, credits, images, videos and live marketplace prices. Turn on Price statistics and every release or master also carries the lowest, median, highest and average asking price across the album's own pressings, not just one pressing's price. Export to JSON, CSV or Excel, or pull results straight into your app through the API.
Why This Scraper?
- Cross-pressing price statistics. The same album can exist as dozens of pressings with prices that differ by an order of magnitude or more. Turn on Price statistics and a record carries the lowest, median, highest and average asking price sampled across the album's pressings, not just one pressing's number.
- Four record kinds. Release (a specific pressing), master (an album across every pressing), artist and label, all sharing one flat schema.
- Nine search filters. Artist, label, genre, style, format, country, year, catalog number and barcode. They combine with a keyword, and they also work completely on their own.
- Full sort control. Order results by relevance, year, title, format, label, catalog number, country, most collected or most wanted, the same sort keys the catalogue itself offers.
- No account required. Every route this actor reads is the public, anonymous catalogue API. Adding your own free Discogs token is optional and only speeds up large pulls and unlocks per-condition valuation.
- Every column always present. Fields a run does not fill ship as
nullrather than being dropped, so repeated runs join cleanly in a warehouse or spreadsheet. - Built for monitoring. Incremental mode returns only new and changed records on a recurring schedule, and a blocked run fails loudly instead of quietly returning an empty dataset.
Use Cases
- Collectors and sellers pricing a pressing: compare an album's own pressings by asking price, total copies for sale and demand, before buying or listing.
- Price tracking over time: schedule the actor with incremental mode on to watch an album's price statistics or a search result move, and get only what changed.
- Music data and analytics projects: build a catalogue dataset of releases, artists and labels with tracklists, credits and identifiers for research or cataloguing tools.
- Marketplace and reselling tools: feed live marketplace numbers (copies for sale, lowest price, demand ratio) into your own pricing or alerting app.
- Label and artist research: pull an artist's discography or a label's release history and sub-labels in one structured run.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
kind | "release" (also "master", "artist", "label") |
recordId / entityId | "release:1000001" / 1000001 |
sourceMode / searchQuery | "search" / "sample album" |
title / name | "Sample Album" (release, master); name on artist and label |
artistName / artistNames | "Sample Artist" / ["Sample Artist"] |
year / country | "1991" / "UK" |
primaryGenre / primaryStyle | "Rock" / "Grunge" |
primaryFormat / primaryLabel | "Vinyl" / "Sample Records" |
catalogNumber / barcodes | "SR-1234" / ["0000000000000"] |
numForSale / lowestPrice / currency | 42 / 12.5 / "USD" (one pressing) |
priceLowest / priceMedian / priceHighest / priceAverage | 8.0 / 24.99 / 89.0 / 30.15 (across pressings, when Price statistics is on) |
priceVersionsSampled / masterVersionsTotal / totalForSaleAcrossVersions | 5 / 120 / 61 |
haveCount / wantCount / wantToHaveRatio | 3400 / 480 / 0.1412 |
ratingAverage / ratingCount | 4.1 / 210 |
priceSuggestionMint ... priceSuggestionPoor | per-condition valuation, only with your own Discogs token |
tracklist / trackCount | full tracklist / 8 (with Read the full record on) |
images / coverImageUrl | image list / cover URL |
url / marketplaceUrl | catalogue page / marketplace listing page |
detailLoaded / priceStatsLoaded | true / true |
scrapedAt | "2026-09-30T12:00:00+00:00" |
changeType / changedFields / firstSeenAt / lastSeenAt | incremental mode: "UPDATED" / ["lowestPrice"] / timestamps |
Artist records also carry realName, profile, nameVariations, aliases, members, groups, externalUrls, contactEmails and contactPhones. Label records also carry profile, contactInfo, parentLabelId, parentLabelName, subLabels, subLabelCount, contactEmails and contactPhones, all taken from the label's or artist's own published profile block.
How to Use
- Pick a mode:
search(keyword and filter searches across the catalogue) orurl(paste release, master, artist or label links or ids). - Search mode: add
searchQueries, choosesearchType, and narrow with any of the filters (artist,label,genre,style,format,country,year,catalogNumber,barcode). Filters work with no keyword at all. Order results withsortByandsortOrder. - Set Max records (
maxItems) to control run size and cost, then click Start. - Turn on
priceStatsfor the cross-pressing price distribution, andfetchDetailsfor the full catalogue entry (tracklist, credits, images). Download the dataset as JSON, CSV or Excel, or read it through the API.
Search by keyword, with cross-pressing price statistics:
{"mode": "search","searchQueries": ["nirvana nevermind"],"searchType": "release","priceStats": true,"maxPriceVersions": 5,"currency": "USD","maxItems": 10}
Filter-only search, no keyword:
{"mode": "search","searchQueries": [],"searchType": "release","label": "Sub Pop","format": "Vinyl","country": "Japan","sortBy": "want","sortOrder": "desc","maxItems": 25}
Paste catalogue links or ids (release, master, artist, label):
{"mode": "url","startUrls": ["https://www.discogs.com/release/249504","m13814","a72872"],"fetchDetails": true}
Daily price monitoring for a search, only what changed:
{"mode": "search","searchQueries": ["blue note 1568"],"priceStats": true,"incrementalMode": true,"stateKey": "blue-note-watch","maxItems": 0}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/discogs-scraper").call(run_input={"mode": "search", "searchQueries": ["nirvana nevermind"], "maxItems": 10})for record in client.dataset(run["defaultDatasetId"]).iterate_items():print(record["title"], record.get("lowestPrice"))
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/discogs-scraper').call({mode: 'search', searchQueries: ['nirvana nevermind'], maxItems: 10,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
URL mode link types
Running URL mode with the link field left untouched now scrapes one example of each link type below instead of nothing. List and search links are walked page by page and share what is left of Max records after the single-record links, split evenly. An entry that matches none of these is skipped with a warning naming it; if nothing usable remains the run stops with a clear message.
| Link | Example | Result |
|---|---|---|
| Release | https://api.discogs.com/releases/249504 or https://www.discogs.com/release/249504 | One full release record |
| Master | https://api.discogs.com/masters/13814 | One full master record |
| Artist | https://api.discogs.com/artists/72872 | One full artist record |
| Label | https://api.discogs.com/labels/895 | One full label record |
| Keyword search | https://api.discogs.com/database/search?q=nirvana&type=release or https://www.discogs.com/search/?q=nirvana&type=release | The search results, with the link's q, type, filters and sort applied |
| Master versions | https://api.discogs.com/masters/13814/versions | Every pressing of the master, up to Max records |
| Artist releases | https://api.discogs.com/artists/72872/releases | The artist's releases and masters, up to Max records |
| Label releases | https://api.discogs.com/labels/895/releases | The label's releases, up to Max records |
| Marketplace page | https://www.discogs.com/sell/release/249504 | The release it lists |
A list link (a master's versions, an artist's or a label's releases) returns the list rows, not the parent master, artist or label record that older versions of this actor returned for the same link; paste the plain master, artist or label link for the parent record. Site links are mapped to the catalogue id they name; the site page itself is never fetched. Search keywords and the artist, label, genre, style, format and country filters are matched as plain text names (no ids needed); a search that matches nothing logs a warning.
Search mode, URL mode and price statistics
Search mode results already carry title, artist, year, country, format, labels, genres, styles, barcode and the have/want counts, at no extra charge. Turn on fetchDetails to also read each result's full catalogue entry (tracklist, credits, matrix numbers, images, videos, notes, rating); in URL mode a single release, master, artist or label link is always read in full and never charged for it, so that toggle changes nothing for those links. List links (a master's versions, an artist's or a label's releases) and search links behave like search mode: base rows by default, and with fetchDetails or priceStats on, each row that is enriched carries one Detail enrichment charge. Turn on priceStats to also walk the album's other pressings and publish the price distribution; this is separate from fetchDetails and can be used alone or together with it. Each result for which either optional lookup succeeds carries one Detail enrichment charge on top of the per-record charge; a lookup that fails still ships the base record, uncharged.
The Results tab has extra views: Price statistics, Release & master details, Artists & labels and Changes (incremental mode), each showing the columns that matter for that task.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset id and the actor skips every record already collected there, so you are not charged twice for the same record. - Incremental mode (
incrementalMode) is for running the same search or url set again and again (for example daily, to watch a price move). Each record is classifiedNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEAREDorEXPIRED(only withemitExpired, and only after a run whose scan was not stopped early; see the note below).stateKeynames or shares the stored state; leave it empty to let the actor derive one from the search, filter and lookup setup. Every returned field counts as a change by default, including prices,numForSaleand the price statistics (priceLowest,priceMedian,priceHighest,priceAverage), because a price move is what monitoring is for; onlyscrapedAtand the derived alias columns (_index,thumb,community, the*_flattext columns,format,catno,barcodeand the snake_case copies) are excluded. List fields inignoreFieldsForChangesto stop a noisy statistic from marking a recordUPDATED. Changing that list on a campaign with saved state can change which records read asUPDATEDon the next run.
A note on Emit expired records and Max records. emitExpired is only produced after a run's live scan reaches a natural end (not stopped early by maxItems or maxPages, and not a resumed run; with several keywords, see the next note). When that condition is met, every tracked record from the state that the live scan did not see this run is returned as EXPIRED, and this batch is not itself limited by maxItems: a small maxItems bounds the live scan, not the size of the EXPIRED batch it can trigger. On a large, long-running monitoring campaign where most of the tracked scope has genuinely disappeared, a capped run can therefore return far more rows, and cost more, than maxItems suggests. If you monitor a large scope with emitExpired on, watch the first few scheduled runs' item counts, or keep maxItems at 0 so the run's own size is the only limit in play.
A note on Emit expired records with several search keywords. With more than one keyword, each keyword gets its own share of maxItems. If one keyword is stopped by its share, the scan counts as stopped early and no EXPIRED rows are produced that run. Use maxItems 0 to scan every keyword fully.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you have not authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where records should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (catalogue search) or url (paste catalogue links or ids). |
searchQueries | array | (none) | Search mode. One or more keywords, each searched separately and given an equal share of Max records. Leave empty for a filter-only search. |
searchType | string | release | Search mode. release, master, artist, label or all. |
artist | string | (none) | Search mode filter, restricts results to this artist. |
label | string | (none) | Search mode filter, restricts results to this record label. |
genre | string | (none) | Search mode filter, one Discogs genre. |
style | string | (none) | Search mode filter, one Discogs style. |
format | string | (none) | Search mode filter, one physical or digital format. |
country | string | (none) | Search mode filter, the country of the pressing. |
year | string | (none) | Search mode filter, a release year or a range such as 1990-1995. |
catalogNumber | string | (none) | Search mode filter, the label catalog number printed on the spine and label. |
barcode | string | (none) | Search mode filter, a barcode or UPC/EAN. |
sortBy | string | relevance | Search mode. relevance, year, title, format, label, catno, country, have (most collected) or want (most wanted). |
sortOrder | string | desc | Search mode. desc or asc, ignored when sortBy is relevance. |
startUrls | array | one example of each link type | URL mode. Catalogue links (/release/<id>, /master/<id>, /artist/<id>, /label/<id>, /sell/release/<id>), api.discogs.com resource links, list links and search links (see the table below), or r<id> / m<id> / a<id> / l<id> shorthand. A plain number is read as a release id. Left untouched, URL mode scrapes one example of each link type instead of nothing. |
urls | array | (none) | Alias for startUrls, entries from both fields are read in order and de-duplicated. |
maxItems | integer | 20 | Stop after this many records across the whole run. 0 for no limit. |
maxPages | integer | (none, no page limit) | Search mode. Each page holds up to 100 records. A hard cap of 10000 pages per keyword or list link applies even when this is empty. |
fetchDetails | boolean | false | Read each result's full catalogue entry. Single release, master, artist and label links are always read in full and never charged for it; list and search links behave like search mode (one Detail enrichment charge per enriched row). |
priceStats | boolean | false | Build the price distribution (lowest, median, highest, average) across an album's pressings, for releases and masters. |
maxPriceVersions | integer | 5 | Only used when Price statistics is on. How many of an album's pressings to sample (maximum 25). |
currency | string | USD | One of 12 currencies for every marketplace price and price statistic. |
resumeFromRunId | string | (none) | Continue one interrupted run without re-collecting or re-charging for records it already returned. |
incrementalMode | boolean | false | Return only new and changed records on a recurring run of the same search or url set. |
stateKey | string | (none) | Name a monitoring campaign, or deliberately share state across differently configured runs. |
emitUnchanged | boolean | false | Also return (and bill) UNCHANGED records. |
emitExpired | boolean | false | Also return (and bill) EXPIRED records, only after a run whose scan was not stopped early, including a keyword stopped by its share of maxItems. |
ignoreFieldsForChanges | array | [] | Field names left out when deciding whether a record changed, for example priceMedian or numForSale. scrapedAt and the derived alias columns (_index, thumb, community, the *_flat columns, format, catno, barcode and the snake_case copies) are ignored by default. Ignored fields are still returned on every row. |
query | array | unset | Hidden alias of searchQueries, so an input written for other Discogs scrapers runs unchanged. The native field wins when both are set. |
type | string | unset | Hidden alias of searchType. A native searchType other than the default release wins when both are set. |
maxResults | integer | unset | Hidden alias of maxItems: one cap for the whole run, no minimum (maxResults: 5 returns at most 5 records). A native maxItems other than the default 20 wins when both are set. |
getDetails | boolean | unset | Hidden alias of fetchDetails. A native fetchDetails set to true wins when both are set. |
yearMin | integer | unset | Hidden alias that builds the start of the year range. |
yearMax | integer | unset | Hidden alias that builds the end of the year range. |
proxyConfig | object | unset | Hidden alias of proxyConfiguration. A native proxyConfiguration other than the default Apify Proxy setting wins when both are set; your own proxy choice is always honoured. |
mcpConnectors | array | (none) | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | (none) | Notion connector only: page under which records are created. |
maxNotifyListings | integer | 50 | Cap on records written to each connector per run. Does not affect the dataset. |
proxyConfiguration | object | Apify Proxy | Connection settings. The default is Apify datacenter proxy and needs no configuration; it needs a paid Apify plan (see Plan Requirement). |
discogsToken | string | (none) | Optional. Your own free Discogs personal access token, see below. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"kind": "release","recordId": "release:1000001","entityId": 1000001,"sourceMode": "search","searchQuery": "sample album","title": "Sample Album","artistName": "Sample Artist","artistNames": ["Sample Artist"],"year": "1991","country": "UK","primaryGenre": "Rock","primaryStyle": "Grunge","primaryFormat": "Vinyl","primaryLabel": "Sample Records","labelNames": ["Sample Records"],"catalogNumber": "SR-1234","barcodes": ["0000000000000"],"genres": ["Rock"],"styles": ["Grunge"],"formatDescriptions": ["Vinyl", "LP", "Album"],"numForSale": 42,"lowestPrice": 12.5,"currency": "USD","blockedFromSale": false,"priceLowest": 8.0,"priceMedian": 24.99,"priceHighest": 89.0,"priceAverage": 30.15,"priceCurrency": "USD","priceVersionsSampled": 5,"priceVersionsPriced": 5,"masterVersionsTotal": 120,"totalForSaleAcrossVersions": 61,"haveCount": 3400,"wantCount": 480,"wantToHaveRatio": 0.1412,"ratingAverage": 4.1,"ratingCount": 210,"trackCount": 8,"url": "https://www.discogs.com/release/1000001","marketplaceUrl": "https://www.discogs.com/sell/release/1000001","detailLoaded": true,"priceStatsLoaded": true,"scrapedAt": "2026-09-30T12:00:00+00:00","changeType": "NEW"}
Plan Requirement
The default proxy setting uses Apify datacenter proxy, which is enough for this actor: no residential proxy is needed. A paid Apify plan is required because the free plan includes no Apify proxy: on a free plan every connection is refused, no backup connection can help, and the run stops with "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required". If a run ends with "Could not load any results page (the requests failed)", that is a connection problem, not an empty search: try again later. When the default connection is unavailable but the backup connection serves pages, the log says "Served over the backup connection (the default connection was unavailable)". If the backup connection cannot load the requested pages either, the run ends with "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later". If you enter your own proxy URLs they are used as given, with no backup connection.
Adding your own free Discogs personal access token is optional: it raises the catalogue's own per-address pacing budget so large pulls finish faster, and it unlocks the per-condition valuation fields that Discogs shows only to a signed-in member.
FAQ
How much does it cost?
Three events exist: Record (one per record returned to the dataset), Detail enrichment (one per record whose optional extras, the full record read via fetchDetails or the price statistics via priceStats, succeeded) and Actor Start (one per run). Unchanged rows suppressed by Incremental mode, failed lookups and records skipped on resume are not charged. The Pricing tab shows the current rates. Use Max records to cap the cost of any run.
Is it legal to scrape Discogs?
This actor collects only publicly available catalogue and marketplace data through Discogs' own documented, anonymous API. You are responsible for how you use the output: follow Discogs' terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Contact details in contactEmails and contactPhones come only from a label's or artist's own public profile block, where they published them themselves.
Can I get only new or changed records 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 records, and unchanged ones are not billed unless you turn on Emit unchanged.
What is the difference between a pressing's price and Price statistics?
lowestPrice and numForSale describe ONE pressing, the exact release you searched or pasted. priceLowest, priceMedian, priceHighest and priceAverage describe the DISTRIBUTION across an album's other pressings, sampled with Price statistics on. A single pressing's lowest price can look cheap or expensive purely by chance; the distribution across pressings is the number that tells you whether that price is actually low or high for the album.
Why did my run fail instead of returning an empty dataset?
If Discogs refuses every request the run stops with a clear message, so "no results matched" is never confused with "nothing could be read". Run it again in a few minutes. A search that genuinely matches nothing, or an incremental run whose records were all unchanged, still succeeds with zero new rows.
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:
| ๐ SeatGeek Scraper Scrape SeatGeek events with ticket price ranges (lowest, highest, average, median)... | ๐ GOAT Scraper Scrape GOAT (goat.com), the sneaker and streetwear resale marketplace. Search or paste... |
| ๐ KREAM Scraper Scrape KREAM (kream.co.kr) sneaker and fashion resale data by keyword search, filters... | ๐งฉ TIDAL Scraper Scrape TIDAL tracks, albums, artists, playlists and public mixes by search phrase or URL... |
| ๐งฉ Deezer Scraper Scrape Deezer by keyword or URL. Extract tracks, albums, artists, playlists, lyrics... | ๐งฉ Anghami Scraper Scrape Anghami's public catalog by keyword or player URL. Rows carry their kind (song... |
๐ 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.