# Discogs Scraper (`s-r/discogs-scraper`) Actor

- **URL**: https://apify.com/s-r/discogs-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Discogs Scraper

Search the Discogs music database and get releases back as rows: title, year, country, label, catalog number, **barcode**, and how many collectors want the pressing against how many own it.

No login and no API key needed. A free Discogs token is supported and roughly doubles the speed, but the actor works without one.

### What you get

- **The barcode (EAN/UPC) on releases that carry one**, filtered so it is actually a barcode. Discogs mixes matrix runouts, rights-society codes like `BIEM/SDRM` and pressing-plant strings into the same field; only 8 to 14 digit codes come back as barcodes. That makes it an exact join key against a shop catalogue
- **`want`, `have` and `want_have_ratio`.** How many collectors are chasing a pressing against how many own it. A ratio above 1 means demand exceeds supply among Discogs users, which is the signal that moves second-hand prices, and it appears nowhere on the rendered page
- **Catalog number, labels, formats, genres, styles, country and year** on every row
- **`master_id`**, which groups every pressing of the same record, so you can collapse 40 reissues into one title
- **The real match count.** `totalMatches` says how many results exist against how many you took, so a 100-row run out of 42.431 never looks like the whole answer
- **Search by anything**: free text, artist, label, barcode, catalog number, genre, style, country, year, format or track title

### Why this reads the API, not the page

Discogs publishes a documented public API and it is simply better than its own HTML. The search page links 26 releases; `api.discogs.com` returns **100 per page** with the full metadata attached, needs no authentication and does not change shape when the site is redesigned.

Scraping the page here would be slower, would return less, and would break more often. The reason to say so out loud is that it is the step most often skipped: check whether the target already offers the data before spending anything on getting past its front end.

### Input

| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
| `q` | string | one field | `nirvana` | Free-text search |
| `type` | select | no | `release` | Release, master, artist or label |
| `artist` | string | no | – | Filter by artist |
| `label` | string | no | – | Filter by label |
| `barcode` | string | no | – | Look up a pressing by EAN/UPC |
| `catno` | string | no | – | Label catalog number |
| `genre` / `style` | string | no | – | Discogs genre and the narrower style |
| `country` / `year` / `format` | string | no | – | Pressing country, year, medium |
| `track` | string | no | – | Releases containing a track with this title |
| `token` | string | no | – | Discogs personal token. Lifts the rate limit from 25 to 60 per minute |
| `limit` | integer | no | `100` | Results to return, 1 to 2000 |

At least one search field is required; the actor refuses an empty search rather than paging the whole database.

### Output

```json
{
  "position": 1,
  "id": 7445961,
  "type": "release",
  "title": "Nirvana - Nirvana",
  "year": "2015",
  "country": "Europe",
  "url": "https://www.discogs.com/release/7445961",
  "labels": [
    "DGC",
    "Sub Pop",
    "Geffen Records"
  ],
  "catalog_number": "0602547378781",
  "barcode": "602547378781",
  "barcodes": [
    "602547378781"
  ],
  "formats": [
    "Vinyl",
    "LP",
    "Compilation",
    "Reissue"
  ],
  "genres": [
    "Rock"
  ],
  "styles": [
    "Grunge",
    "Alternative Rock"
  ],
  "master_id": 156308,
  "want": 1760,
  "have": 22683,
  "want_have_ratio": 0.078,
  "cover_image": "https://i.discogs.com/..."
}
```

### Use cases

**Matching a shop listing to a pressing.** Take the barcode off a marketplace listing and look it up here. You get the exact pressing, its year, country and label, plus how sought-after it is. Guessing from a title cannot do this: the same album has hundreds of pressings and they are not worth the same money.

**Finding pressings worth buying.** Sort by `want_have_ratio`. A record with 88 wants and 2 haves is scarce and chased; one with 127 wants and 4.377 haves is common. That single ratio separates the two, and it is what a dealer is actually paying attention to.

**Building a catalogue for a genre or label.** `label=Sub Pop` returns 9.410 releases; `genre=Rock&style=Grunge` returns 42.431. Set `limit` and you have the reference list.

**Collapsing reissues.** Group your results by `master_id` to see how many times a record has been pressed, which tells you whether a copy is rare or simply old.

**Enriching an inventory.** Feed catalog numbers or barcodes from your own stock and get back genre, style, year and demand for each.

### How it compares

| | this actor | the other 19 Discogs actors |
|---|---|---|
| Per 1.000 results | **$1,00** | mostly no per-item rate declared |
| Results per request | **100** | not stated |
| Barcode, cleaned of non-barcodes | **yes** | not stated |
| Collector demand (want / have / ratio) | **yes** | not stated |
| Real match count returned | **yes** | no |
| Monthly users | new | best is **4** |

Honest about the other side: twenty Discogs actors exist and between them they have eighteen monthly users, so this is a small market and nobody in it has proven anything. The upside is that nothing has to be displaced.

### Pricing

Two events. `run_start` costs $0,0010 per run. `record` costs $0,0010 per result written to the dataset, which is $1,00 per 1.000.

### Limits and gotchas

- **The rate limit is Discogs', not ours.** 25 requests a minute unauthenticated, 60 with a token, and the actor paces itself off the `X-Discogs-Ratelimit` header rather than a guess. A 2.000-row run is 20 requests, so it takes about 48 seconds anonymously and 20 with a token.
- **Barcode coverage is partial and honest.** Roughly 40 to 50% of releases carry one; older and independent pressings often predate barcodes entirely. `withBarcode` in the summary gives the run's coverage.
- **A `release` is one pressing, a `master` is the record.** Searching releases for a famous album returns dozens of near-identical rows from different countries and years. Use `type: master` when you want one row per record.
- **`want` and `have` are Discogs users**, not the world. They measure that community's collections, which skews toward vinyl and away from mainstream CDs.
- **The result count can be enormous.** A bare genre search matches tens of thousands. `totalMatches` tells you what you are sampling from; the actor caps at 2.000 per run.
- **No pricing data.** The marketplace prices live behind a different, authenticated endpoint and are not returned here.

### FAQ

**Do I need a Discogs account?**
No. It runs anonymously at 25 requests a minute. A free personal token raises that to 60 and is worth adding for large runs.

**Can I look a record up by barcode?**
Yes, that is the `barcode` field, and it is the most precise way to match a shop listing to a specific pressing.

**Why do some releases have no barcode?**
Because many pressings, especially pre-1980s and independent ones, never had one. The field is null rather than guessed.

**What is want\_have\_ratio actually telling me?**
How many Discogs users want that exact pressing divided by how many own it. Above 1 is scarce and chased; well below 1 is common.

**Does it return marketplace prices?**
No. Those sit behind an authenticated endpoint this actor does not use.

### Related Actors

- [Beslist.nl Scraper](https://apify.com/s-r/beslist-scraper) — Dutch price comparison, also keyed on EAN
- [EAN UPC GTIN Product Lookup](https://apify.com/s-r/ean-upc-gtin-product-lookup-database) — resolve a barcode to product data
- [eMAG Scraper](https://apify.com/s-r/emag-scraper) — retail listings across Romania, Bulgaria and Hungary

# Actor input Schema

## `q` (type: `string`):

Free-text search across the Discogs database. Combine with the fields below to narrow it.

## `type` (type: `string`):

What to return. A release is one specific pressing; a master groups all pressings of the same record.

## `artist` (type: `string`):

Filter by artist name.

## `label` (type: `string`):

Filter by record label.

## `barcode` (type: `string`):

Look a pressing up by its barcode. This is the exact way to match a shop listing to a Discogs release.

## `catno` (type: `string`):

Label catalog number, for example SP55.

## `genre` (type: `string`):

Discogs genre, for example Rock or Electronic.

## `style` (type: `string`):

Discogs style, which is narrower than genre, for example Grunge.

## `country` (type: `string`):

Country of the pressing, for example Netherlands.

## `year` (type: `string`):

Release year.

## `format` (type: `string`):

Vinyl, CD, Cassette, LP and so on.

## `track` (type: `string`):

Find releases containing a track with this title.

## `token` (type: `string`):

Optional. Raises the rate limit from 25 to 60 requests per minute, which makes large runs about twice as fast. Create one for free in your Discogs account settings.

## `limit` (type: `integer`):

How many results to return, 1 to 2000. A page carries 100.

## `retries` (type: `integer`):

Retry attempts per request.

## Actor input object example

```json
{
  "q": "nirvana nevermind",
  "type": "release",
  "artist": "Nirvana",
  "label": "Sub Pop",
  "barcode": "602547378781",
  "genre": "Rock",
  "style": "Grunge",
  "year": "1991",
  "format": "Vinyl",
  "limit": 100,
  "retries": 3
}
```

# Actor output Schema

## `results` (type: `string`):

One row per release, master, artist or label.

## `summary` (type: `string`):

Results returned against total matches, barcode and community-stat coverage, and the rate limit in force.

## `errors` (type: `string`):

Failures with a code and a redacted message.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "q": "nirvana",
    "type": "release",
    "limit": 100,
    "retries": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/discogs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "q": "nirvana",
    "type": "release",
    "limit": 100,
    "retries": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/discogs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "q": "nirvana",
  "type": "release",
  "limit": 100,
  "retries": 3
}' |
apify call s-r/discogs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/discogs-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yVVchs8CghZ6ftxYl/builds/95209tH4f4F0h8WeB/openapi.json
