# Spotify Scraper — Play Counts, Monthly Listeners & Playlists (`innolabs/spotify-scraper`) Actor

Spotify scraper API: tracks with play counts, artists with monthly listeners, albums, playlists and search results. No login or developer key. JSON/CSV/Excel.

- **URL**: https://apify.com/innolabs/spotify-scraper.md
- **Developed by:** [Tristan Leroux](https://apify.com/innolabs) (community)
- **Categories:** For creators, Marketing
- **Security:** Limited permissions
- **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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Spotify Scraper — Play Counts, Monthly Listeners, Albums & Playlists

Scrape **Spotify tracks with play counts, artists with monthly listeners and top cities,
albums and playlists** — from links or keyword search. Get stream counts for every track of
an album or playlist, an artist's top 10 tracks with their plays, world rank, followers,
biography and social links, album labels, UPCs and copyrights, and playlist followers. No
Spotify account, no login and no developer key. Export as JSON, CSV or Excel, or pull the
data through the API.

### What does Spotify Scraper do?

Spotify Scraper reads the public data that the Spotify web player shows to anyone and
returns it as clean rows. Each row has a `type`:

- **Tracks** — name, artists, album (name, release date, cover), duration, explicit flag,
  **play count** (total streams), popularity (0–100), track and disc number, **ISRC**,
  30-second preview MP3 URL, and for playlist tracks the position and the date the track
  was added.
- **Artists** — **monthly listeners**, followers, **world rank**, **top 5 cities** with
  listener counts, genres, popularity, verified badge, biography, profile/header/gallery
  images, social links (Instagram, Facebook, Twitter, Wikipedia…), top 10 tracks with play
  counts, up to 20 related artists ("Fans also like"), and the number of albums, singles and
  compilations.
- **Albums** — name, type (album/single/compilation/EP), release date, label, copyrights,
  **UPC**, popularity, artists, cover images, number of tracks, the **total play count of
  the album** and a track list with each track's play count.
- **Playlists** — name, description, owner, **followers**, number of tracks and cover.
- **Search** — enter keywords and choose tracks, artists, albums or playlists; every result
  comes with the same details as a link would.

Artists, albums and playlists can be expanded into one row per track (on by default), so a
single playlist link gives you every song with its play count.

### Use cases

- **Music marketers and labels** — track play counts of your releases and your competitors'
  over time, and see which cities listen most to an artist before planning a tour or ads.
- **Artist managers and A\&R** — compare monthly listeners, followers and world rank across
  a roster, or scout fast-growing artists from search results.
- **Playlist pitching and curators** — measure playlist reach (followers) and see which
  tracks a playlist added recently and how big they are.
- **Music data analysts and researchers** — build datasets of tracks with ISRC, release
  dates, labels and stream counts for catalog valuation or trend analysis.
- **Rights and royalty teams** — match catalog by ISRC/UPC and estimate streams per track.
- **Content creators and media** — pull up-to-date stream counts and top tracks for
  articles, charts and social posts.

### How much does it cost?

You pay only for the rows you get (pay-per-event). Duplicates and rows over your
`maxItems` limit are never charged.

| Event | What you pay for | Free plan | Paid plans (from) |
| --- | --- | --- | --- |
| `track` | One track row with play count | $1.00 per 1,000 | $0.50 per 1,000 |
| `artist` | One artist row (monthly listeners, top cities, top tracks…) | $2.00 per 1,000 | $1.50 per 1,000 |
| `album` | One album row (label, UPC, track list with play counts) | $2.00 per 1,000 | $1.50 per 1,000 |
| `playlist` | One playlist row (owner, followers, track count) | $2.00 per 1,000 | $1.50 per 1,000 |

"Paid plans (from)" is the Gold-and-above price; Bronze and Silver plans sit in between.
Apify also charges a tiny actor-start fee ($0.00005 per run).

Worked examples (Free plan prices):

1. **Play counts of a 500-song playlist** — 1 playlist row + 500 track rows:
   1 × $0.002 + 500 × $0.001 = **$0.50** (Gold: $0.25).
2. **Weekly report on 100 artists with their top tracks** — 100 artist rows + 1,000 top
   track rows: 100 × $0.002 + 1,000 × $0.001 = **$1.20 per week** (Gold: $0.65).

The Apify Free plan includes $5 monthly credit, enough for about 5,000 tracks with play
counts every month.

### How to use Spotify Scraper

In Apify Console:

1. Open Spotify Scraper and click **Try for free**.
2. Paste links into **Spotify URLs** — tracks, albums, artists or playlists, copied from the
   Spotify app ("Share" → "Copy link") or from open.spotify.com. The form is prefilled with
   an artist and a playlist. Or type keywords into **Search queries** and pick what to
   search for.
3. Choose whether artists, albums and playlists should also be expanded into track rows
   (all on by default) and, if you like, a cap per source.
4. Click **Start**. The prefilled input finishes in a few seconds; a run with 1,250 rows
   (including a 1,000-track playlist) took under a minute.
5. Open the **Output** tab and export the dataset as JSON, CSV, Excel or HTML.

Through the API:

1. Get your API token in Apify Console → Settings → Integrations.
2. Call the actor with your input JSON (see [Integrations and API](#integrations-and-api)).
3. Read the dataset items from the run.

### Input

Fill in `startUrls`, `searchQueries` or both.

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | – | Track, album, artist or playlist links (`https://open.spotify.com/album/...`, with or without `?si=`, `/intl-xx/` or `/embed/`) or URIs (`spotify:playlist:...`). |
| `searchQueries` | array | – | Keywords to search on Spotify. |
| `searchType` | string | `track` | What searches return: `track`, `artist`, `album` or `playlist`. |
| `maxSearchResults` | integer | `20` | Results per query (1–1000). |
| `includeArtistTopTracks` | boolean | `true` | Also output each artist's top tracks (up to 10) as track rows. |
| `includeAlbumTracks` | boolean | `true` | Also output each album's tracks as track rows. |
| `includePlaylistTracks` | boolean | `true` | Also output each playlist's tracks as track rows. |
| `maxTracksPerSource` | integer | `0` | Cap on track rows per artist, album or playlist; `0` = all. |
| `maxItems` | integer | `1000` | Hard cap on all rows in the run. |
| `proxyConfiguration` | object | Apify Proxy | Proxy settings; the default works. |
| `debug` | boolean | `false` | Log every request. |

Example — an artist profile with top tracks, a full album and the first 200 songs of a
playlist:

```json
{
    "startUrls": [
        "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb",
        "https://open.spotify.com/album/6dVIqQ8qmQ5GBnJ9shOYGE",
        "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
    ],
    "maxTracksPerSource": 200
}
```

Example — top 100 "lofi study" tracks with play counts:

```json
{
    "searchQueries": ["lofi study"],
    "searchType": "track",
    "maxSearchResults": 100
}
```

Example — monthly listeners of the artists found for two keywords, without track rows:

```json
{
    "searchQueries": ["k-pop", "afrobeats"],
    "searchType": "artist",
    "maxSearchResults": 50,
    "includeArtistTopTracks": false
}
```

### Output

Examples below come from a real run on 2026-11-05 (long fields shortened).

#### Track

```json
{
    "type": "track",
    "id": "70LcF31zb1H0PyJoS1Sx1r",
    "uri": "spotify:track:70LcF31zb1H0PyJoS1Sx1r",
    "url": "https://open.spotify.com/track/70LcF31zb1H0PyJoS1Sx1r",
    "name": "Creep",
    "artists": [{ "id": "4Z8W4fKeB5YxbusRsdQVPb", "name": "Radiohead" }],
    "album": {
        "id": "3gBVdu4a1MMJVMy6vwPEb8",
        "name": "Pablo Honey",
        "releaseDate": "1993-02-22",
        "images": [{ "url": "https://i.scdn.co/image/ab67616d0000b273ec548c00d3ac2f10be73366d", "width": 640, "height": 640 }]
    },
    "durationMs": 238640,
    "explicit": true,
    "playCount": 3232528965,
    "popularity": 94,
    "trackNumber": 2,
    "discNumber": 1,
    "isrc": "GBAYE9200070",
    "previewUrl": "https://p.scdn.co/mp3-preview/f3d864283774529a2378100c912bfacb614db751",
    "playable": true,
    "context": { "type": "artist", "id": "4Z8W4fKeB5YxbusRsdQVPb", "name": "Radiohead" },
    "position": null,
    "addedAt": null,
    "source": "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb"
}
```

Playlist tracks have `context.type: "playlist"`, `position` (1 = first song) and `addedAt`
(e.g. `"2026-08-07T04:02:23.096Z"`). Search results have `context: null` and
`source: "search: lofi study"`.

#### Artist

```json
{
    "type": "artist",
    "id": "4Z8W4fKeB5YxbusRsdQVPb",
    "url": "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb",
    "name": "Radiohead",
    "verified": true,
    "followers": 17486682,
    "monthlyListeners": 46341281,
    "worldRank": 80,
    "topCities": [
        { "city": "London", "country": "GB", "region": "ENG", "listeners": 691086 },
        { "city": "Mexico City", "country": "MX", "region": "CMX", "listeners": 682018 }
    ],
    "genres": ["art rock", "alternative rock"],
    "popularity": 87,
    "biography": "Radiohead are a touchstone for all that is fearless and adventurous in rock…",
    "images": [{ "url": "https://i.scdn.co/image/ab6761610000e5eb959527d2fabc9c64287e57b9", "width": 640, "height": 640 }],
    "headerImage": { "url": "https://image-cdn-fa.spotifycdn.com/image/ab6761860000eab163fffb29c4a76743c90bfea3", "width": 2660, "height": 1140 },
    "externalLinks": [
        { "name": "INSTAGRAM", "url": "https://instagram.com/radiohead" },
        { "name": "TWITTER", "url": "https://twitter.com/radiohead" }
    ],
    "topTracks": [
        { "id": "70LcF31zb1H0PyJoS1Sx1r", "name": "Creep", "playCount": 3232528965, "albumId": "3gBVdu4a1MMJVMy6vwPEb8" },
        { "id": "10nyNJ6zNy2YVYLrcwLccB", "name": "No Surprises", "playCount": 1492684298, "albumId": "6dVIqQ8qmQ5GBnJ9shOYGE" }
    ],
    "albumsCount": 15,
    "singlesCount": 30,
    "compilationsCount": 0,
    "relatedArtists": [
        { "id": "3yY2gUcIsjMr8hjo51PoJ8", "name": "The Smiths", "url": "https://open.spotify.com/artist/3yY2gUcIsjMr8hjo51PoJ8" }
    ],
    "source": "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb"
}
```

#### Album

```json
{
    "type": "album",
    "id": "6dVIqQ8qmQ5GBnJ9shOYGE",
    "url": "https://open.spotify.com/album/6dVIqQ8qmQ5GBnJ9shOYGE",
    "name": "OK Computer",
    "albumType": "ALBUM",
    "releaseDate": "1997-05-28",
    "label": "XL Recordings",
    "copyrights": [{ "text": "1997 XL Recordings Ltd", "type": "C" }],
    "totalTracks": 12,
    "artists": [{ "id": "4Z8W4fKeB5YxbusRsdQVPb", "name": "Radiohead" }],
    "upc": "634904078164",
    "popularity": 90,
    "totalPlayCount": 4859932935,
    "tracks": [
        { "id": "7c378mlmubSu7NGkLFa4sN", "name": "Airbag", "trackNumber": 1, "discNumber": 1, "durationMs": 287880, "explicit": false, "playCount": 107766812 }
    ],
    "source": "https://open.spotify.com/album/6dVIqQ8qmQ5GBnJ9shOYGE"
}
```

#### Playlist

```json
{
    "type": "playlist",
    "id": "37i9dQZF1DXcBWIGoYBM5M",
    "url": "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M",
    "name": "Today’s Top Hits",
    "description": "The hottest 50. Cover: Tame Impala",
    "owner": { "id": "spotify", "name": "Spotify", "url": "https://open.spotify.com/user/spotify" },
    "followers": 33626504,
    "totalTracks": 50,
    "images": [{ "url": "https://i.scdn.co/image/ab67706f00000002960019ea66cba66a44fdd4c2", "width": null, "height": null }],
    "source": "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
}
```

Field notes:

- `playCount` is Spotify's all-time stream count of the track, as shown in the Spotify
  app.
- `releaseDate` follows Spotify's precision: `1997-05-28`, `1997-05` or `1997`.
- `popularity` is Spotify's 0–100 score; `worldRank` is `null` for artists outside the
  ranking.
- `previewUrl` is a 30-second MP3; Spotify does not offer previews for every track.
- `source` is the link or search that produced the row.

### Integrations and API

Run the actor and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/innolabs~spotify-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls": ["https://open.spotify.com/album/6dVIqQ8qmQ5GBnJ9shOYGE"]}'
```

Python with [apify-client](https://docs.apify.com/api/client/python):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("innolabs/spotify-scraper").call(
    run_input={
        "startUrls": ["https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"],
        "maxTracksPerSource": 100,
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["type"] == "track":
        print(item["position"], item["name"], item["playCount"])
```

- **Make, Zapier, n8n** — start the actor from a scenario and send rows to Google Sheets,
  Airtable, Notion or Slack.
- **Scheduling** — create a daily or weekly schedule in Apify Console to build a history of
  play counts and monthly listeners.
- **Webhooks** — trigger your pipeline when a run finishes.
- **AI agents (MCP)** — connect Claude, Cursor or other MCP clients through the Apify MCP
  server at https://mcp.apify.com and let your agent look up Spotify stats on demand.

### FAQ

#### Do I need a Spotify account or API key?

No. The scraper uses only what the public Spotify web player shows to visitors who are not
logged in. You do not need a Spotify account, a developer app or an API key.

#### How fresh are play counts and monthly listeners?

They are read live at run time. Spotify updates play counts about once a day and monthly
listeners daily (a rolling 28-day count), so a daily schedule captures every change.

#### Can I get all tracks of a big playlist?

Yes. Playlists are read 100 tracks at a time up to their full length (Spotify allows up to
10,000 tracks). Use `maxTracksPerSource` or `maxItems` to keep the cost under control.

#### What if a link is wrong or an item was removed?

Each link is processed on its own. A wrong link, a removed album or an unsupported page
(podcasts, user profiles) is listed in the run log and in the run's `SUMMARY` record, and
the rest of the run continues. You are not charged for failed items. If every input fails,
the run is marked as failed with the reason.

#### Is it legal to scrape Spotify?

The scraper only collects public catalog data (tracks, artists, albums, public playlists)
that Spotify shows to anyone without logging in, and no personal account data. Make sure
your use of the data complies with Spotify's terms and the laws that apply to you.

#### Do I need proxies?

No setup is needed. The default Apify Proxy setting works, and the scraper waits and
retries automatically when Spotify rate-limits.

### Limits

- Podcasts, episodes, audiobooks and user profiles are not supported; short `spotify.link`
  links must be opened first and the open.spotify.com link copied.
- Artist top tracks are Spotify's top 10 for the artist; full discographies are not
  expanded (add the album links you need).
- Each track is delivered once per run, except playlist tracks, which are delivered once per
  playlist so every playlist's track list stays complete. A track already delivered from an
  artist's top tracks is not repeated in that artist's album.
- `previewUrl` is filled for search results, single tracks, artist top tracks, the first 100
  tracks of an album and the first 100 tracks of a playlist; later playlist tracks have
  `null`.
- Search returns at most 1,000 results per query (Spotify's search depth).
- Genres and popularity come from a second Spotify service; if it rate-limits a large run,
  the remaining rows keep all other fields and leave `genres`, `popularity`, `isrc` and
  `upc` empty instead of failing.

# Changelog

This Actor's version history is a separate document: https://apify.com/innolabs/spotify-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

open.spotify.com links to tracks, albums, artists or playlists (e.g. https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb), or spotify: URIs (spotify:album:6dVIqQ8qmQ5GBnJ9shOYGE). Share links with ?si=… and localized /intl-xx/ links work too.

## `searchQueries` (type: `array`):

Keywords to search on Spotify, e.g. 'daft punk' or 'lofi study'. Each query returns up to 'Results per search' items of the type chosen below.

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

What the search queries return: tracks (with play counts), artists, albums or playlists.

## `maxSearchResults` (type: `integer`):

How many search results to take per query (1–1000, Spotify's search depth).

## `includeArtistTopTracks` (type: `boolean`):

For every artist, also output its top tracks (up to 10) as track rows with play counts.

## `includeAlbumTracks` (type: `boolean`):

For every album, also output each track as a row with play count, ISRC and popularity. The album row always contains a short track list with play counts.

## `includePlaylistTracks` (type: `boolean`):

For every playlist, also output its tracks as rows with play count, position and date added.

## `maxTracksPerSource` (type: `integer`):

Cap on track rows from each artist, album or playlist. 0 = all (playlists can hold up to 10,000 tracks).

## `maxItems` (type: `integer`):

Hard cap on dataset rows for the whole run (tracks, artists, albums and playlists together). The run stops cleanly when reached.

## `proxyConfiguration` (type: `object`):

Apify Proxy settings. The default datacenter proxy works for Spotify; the scraper waits and retries when Spotify rate-limits.

## `debug` (type: `boolean`):

Log every request with its status code.

## Actor input object example

```json
{
  "startUrls": [
    "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb",
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
  ],
  "searchType": "track",
  "maxSearchResults": 20,
  "includeArtistTopTracks": true,
  "includeAlbumTracks": true,
  "includePlaylistTracks": true,
  "maxTracksPerSource": 0,
  "maxItems": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "debug": false
}
```

# Actor output Schema

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

All rows produced by the run: tracks, artists, albums and playlists (field 'type').

# 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 = {
    "startUrls": [
        "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb",
        "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("innolabs/spotify-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 = { "startUrls": [
        "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb",
        "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("innolabs/spotify-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 '{
  "startUrls": [
    "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb",
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
  ]
}' |
apify call innolabs/spotify-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,innolabs/spotify-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/Mr9TyXihLBODqdweg/builds/JLgtU83yAkI0ejVcy/openapi.json
