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

Scrape Spotify tracks, artists, albums, playlists and podcasts: play counts, monthly listeners, followers, world rank, top cities, playlist tracks. No login.

- **URL**: https://apify.com/tortuga/spotify-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 track, artist, album, playlist or podcasts

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?

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 & Playlists

Scrape public Spotify data the way the Spotify web player shows it to a logged-out visitor: **exact play counts**
(stream counts) for every track, **monthly listeners**, followers, world rank and **top cities** of artists, albums
with the play count of every track, playlists with **all their tracks and the date each was added**, podcasts and
episodes, and keyword search. Paste Spotify links or search terms; no Spotify account, API key or login needed.

### What data does Spotify Scraper extract?

| Input | One row with |
|---|---|
| Track URL | `title`, `artist`, `artists`, `albumTitle`, `releaseDate`, **`plays`** (exact play count), `durationSec`, `explicit`, `trackNumber`, `hasMusicVideo`, `artworkUrl`, `cLine`/`pLine` (copyright) |
| Artist URL | `name`, `verified`, **`monthlyListeners`**, `followers`, `worldRank`, **`topCities`** (city, country, listeners), `topTracks` (10, with play counts), `biography`, `socialLinks` (Instagram, TikTok, Wikipedia ...), `albums` / `singles` / `compilations` with release dates, `latestRelease`, `relatedArtists`, `upcomingConcerts`, `avatarUrl`, `bannerUrl` |
| Album URL | `title`, `artist`, `releaseDate`, `labelName`, `cLine`/`pLine`, `totalTracks`, `totalPlays`, `tracks` (every track with **`plays`**, duration, explicit flag) |
| Playlist URL | `title`, `description`, `ownerName`, `ownerUsername`, `followers`, `totalTracks`, `artworkUrl`, plus **one row per track** with `position`, `addedAt`, `addedBy`, `plays`, `bpm`, `musicalKey`, `camelotKey` and all track fields |
| Podcast (show) URL | `title`, `publisher`, `description`, `rating`, `ratingCount`, `topics`, `totalEpisodes`, plus the latest episodes as rows |
| Episode URL | `title`, `description`, `releaseDate`, `durationSec`, `explicit`, `previewUrl`, `showTitle` |
| Search term | tracks, artists, albums, playlists, podcasts or episodes in Spotify's ranking, with `searchRank` (full details per result by default) |

Every row has `type`, `id`, `uri`, `url` and `scrapedAt`. Field names match our SoundCloud Scraper, so datasets
from both can be merged.

### How to get Spotify play counts for tracks and albums

Paste track or album links into **Spotify URLs, URIs or IDs**:

```json
{
  "urls": [
    "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
    "https://open.spotify.com/album/4eLPsYPBmXABThSJ821sqY"
  ]
}
```

An album comes back as one row with every track and its play count (real output, shortened):

```json
{
  "type": "album",
  "title": "50 (10th Anniversary Deluxe Edition)",
  "artist": "Rick Astley",
  "releaseDate": "2026-06-15",
  "labelName": "BMG Rights Management GmbH",
  "totalTracks": 15,
  "totalPlays": 34971199,
  "tracks": [
    { "title": "Keep Singing", "trackNumber": 1, "durationSec": 238.5, "explicit": false, "plays": 6826068 },
    { "title": "Angels on My Side", "trackNumber": 2, "durationSec": 215.7, "explicit": false, "plays": 10590424 }
  ],
  "url": "https://open.spotify.com/album/2WlZ6L68eq4Wy7QUSI2ffK"
}
```

`plays` is the exact number Spotify shows on the track and album pages (Spotify updates it about once a day), not
the 1-100 popularity score of Spotify's developer API.

### How to scrape Spotify monthly listeners and top cities of an artist

Add artist links (`https://open.spotify.com/artist/...` or `spotify:artist:...`). Each artist row holds monthly
listeners, followers, world rank (Spotify ranks the top 500 artists; `null` below that), the top 5 cities with
listener counts, the 10 most played tracks with play counts, the biography and social links. With **Full artist
discography** on (default) the row lists every album, single and compilation with its release date.

```json
{
  "type": "artist",
  "name": "Rick Astley",
  "verified": true,
  "monthlyListeners": 8469649,
  "followers": 1621200,
  "worldRank": null,
  "topCities": [
    { "city": "Mexico City", "country": "MX", "region": "CMX", "listeners": 189431 },
    { "city": "Santiago", "country": "CL", "region": "RM", "listeners": 182604 }
  ],
  "topTracks": [
    { "title": "Never Gonna Give You Up - 2022 Remaster", "plays": 1189869737, "durationSec": 213.6 }
  ],
  "socialLinks": [{ "network": "instagram", "url": "https://instagram.com/officialrickastley" }],
  "albumCount": 12,
  "singleCount": 44,
  "url": "https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt"
}
```

### How to export all tracks of a Spotify playlist

Add playlist links. You get one row with the playlist's details (followers, owner, description, track count) and
then one row per track in playlist order, including the date it was added, who added it (for collaborative and user
playlists), its play count, BPM and musical key. Use **Max tracks per playlist** to stop early, or switch off
**Output playlist tracks** to get only the playlist details.

```json
{
  "type": "track",
  "title": "pop it",
  "artist": "Gunna",
  "plays": 1533246,
  "durationSec": 138.9,
  "explicit": true,
  "bpm": 128,
  "musicalKey": "E minor",
  "camelotKey": "9A",
  "playlistTitle": "RapCaviar",
  "position": 1,
  "addedAt": "2026-10-09T04:02:54.784Z",
  "url": "https://open.spotify.com/track/3LVkyYg0PSo8XInTPKKhZM"
}
```

### How to search Spotify by keyword

Fill **Search terms** and pick **Search for** (tracks, artists, albums, playlists, podcasts or episodes). Results
come in Spotify's own order with `searchQuery` and `searchRank`. Spotify's search list does not show play counts,
listeners or followers, so **Full details for search results** (on by default) opens each result once to add them;
switch it off for a quicker, lighter list. Spotify itself returns about 100 results per term and type.

### Spotify podcasts and episodes

Podcast (show) links give the show's publisher, description, rating, topics and episode count, plus the latest
episodes (**Episodes per podcast**, default 20) with title, description, release date, duration and a preview
clip URL. Episode links give the same episode fields.

### Does it work without login or a Spotify API key?

Yes. The Actor reads the same public data the Spotify web player loads for a visitor who is not logged in, with a
temporary anonymous web-player session. You do not need a Spotify account, a developer app or an API key, and the
Actor never logs in. It runs on Apify's datacenter proxy; no residential proxy is needed.

### Monitor changes on a schedule

Turn on **Only new or changed items** and the Actor remembers what earlier runs of the same input returned. A
scheduled run then outputs a track again only when its play count changed, an artist when monthly listeners,
followers or world rank changed, an album when its total plays changed, a playlist when its followers, track count,
title or description changed, plus only the tracks newly added to each playlist (and new episodes of a podcast, new
results of a search). Unchanged items are dropped before they are saved, so they are not charged. Save the input as
a task and add a Schedule in Apify (for example daily); give each watch its own **Monitoring key** if several
schedules share an input. Output items get `changeType` (`new` or `changed`) and, for changed items,
`previousValues` with the old numbers, so you can chart play-count and listener growth day by day.

### Pricing

Pay per result: **$0.0028 per track, artist, album, playlist, podcast, episode or search result** (an album with all
its tracks and play counts is one result) and **$0.001 per playlist track or podcast episode listed** from a playlist
or show link. Platform usage is small (about $0.015 per 1,000 rows in our tests).

### Fields not available

ISRC and UPC codes, genres and Spotify's 0-100 popularity score are only in Spotify's developer API (which needs an
app and limits requests), not in what the web player shows, so they are not included. 30-second previews are only
available for podcast episodes. Private playlists, user libraries and listening history are never accessed.

### Is it legal to scrape Spotify?

The Actor only reads what Spotify shows to any logged-out visitor: public catalog data (tracks, albums, artists,
public playlists, podcasts) and the public display names Spotify shows for playlist owners and contributors. It does
not log in, does not access private playlists or accounts, and does not download audio. Music, artwork and texts
belong to their rights holders; check Spotify's terms and data-protection rules for your use case. You are
responsible for how you use the data.

### Support

Missing a field or found a link that fails? Open an issue in the **Issues** tab with your input. Issues are usually
answered within a day.

# Actor input Schema

## `urls` (type: `array`):

Track, artist, album, playlist, podcast (show) or episode links from open.spotify.com, spotify: URIs (spotify:artist:0gxyHStUsqpMadRV0Di1Qt) or spotify.link short links. A bare 22-character ID is read as a track ID. Tracks give play counts; artists give monthly listeners, followers, world rank, top cities, top tracks and discography; albums give every track with its play count; playlists give their details plus every track with the date it was added.

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

Keywords to search on Spotify, e.g. lofi hip hop or workout playlist. Each term returns results of the type chosen below, in Spotify's own ranking (up to the per-term limit).

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

What the search terms should return.

## `maxResultsPerSearch` (type: `integer`):

How many results to take per search term. Spotify's search itself usually stops after about 100 results per term and type.

## `searchDetails` (type: `boolean`):

Open every search result to add what the search list does not show: play counts for tracks, monthly listeners/followers/top cities for artists, label and per-track play counts for albums, followers and track count for playlists, episode count for podcasts. One extra request per result; turn off for faster, lighter results.

## `includeDiscography` (type: `boolean`):

For artist URLs, list every album, single and compilation with its release date (otherwise only the 10 latest of each, as shown on the artist page).

## `playlistTracks` (type: `boolean`):

For playlist URLs, also output every track of the playlist as its own row (position, date added, added by, play count, BPM, key). Off = only the playlist's details (followers, owner, description, track count).

## `maxTracksPerPlaylist` (type: `integer`):

Stop after this many tracks of each playlist (in playlist order). Empty = all tracks.

## `maxEpisodesPerShow` (type: `integer`):

For podcast (show) URLs, how many of the latest episodes to output as rows (title, description, release date, duration). 0 = only the show's details.

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

Stop after this many dataset rows in total (tracks, artists, albums, playlists, playlist tracks, shows, episodes). Keeps cost predictable.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this input returned and output only new items or items whose numbers changed: track play counts, artist monthly listeners/followers/world rank, album play totals, playlist followers/track count, and tracks newly added to a playlist. Use with a Schedule; unchanged items are not charged.

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

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

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

Apify Proxy (datacenter) works for Spotify and is the default; no residential proxy needed.

## Actor input object example

```json
{
  "urls": [
    "https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt",
    "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT"
  ],
  "searchType": "tracks",
  "maxResultsPerSearch": 50,
  "searchDetails": true,
  "includeDiscography": true,
  "playlistTracks": true,
  "maxEpisodesPerShow": 20,
  "maxItems": 100,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "urls": [
        "https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt",
        "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/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 = {
    "urls": [
        "https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt",
        "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/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 '{
  "urls": [
    "https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt",
    "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/spotify-scraper --silent --output-dataset

```

## MCP server setup

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