# Free Spotify Playlist Intelligence (`s-r/free-spotify-playlist-intelligence`) Actor

- **URL**: https://apify.com/s-r/free-spotify-playlist-intelligence.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Social media
- **Stats:** 1 total users, 1 monthly users, 0.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Free Spotify Playlist Intelligence — Tracklist, Followers & Editorial Flag Scraper

Scrape any public Spotify playlist for full track list, follower count,
owner info, editorial flag, and run-over-run diffs (added / removed /
moved tracks). Built for **Spotify playlist tracking**, **editorial
playlist monitoring**, and **playlist follower count** intelligence.
$0.01 per playlist.

### What you get

- Playlist metadata: `name`, `description`, `image_url`,
  `total_tracks`, `uri`
- `followers` — exact follower count (e.g. `33,847,291` for Today's
  Top Hits). The official Spotify Web API does still expose this,
  but only with OAuth.
- `is_editorial` — boolean flag, true when the owner is `spotify`
  itself (i.e. it's an official Spotify-curated editorial playlist
  like RapCaviar, Today's Top Hits, mint)
- `owner` — uri, name, username
- `tracks[]` — full paginated tracklist with `position`, `name`,
  `artists[]`, `album.name`, `album.cover_url`, `duration_ms`,
  `explicit`, `added_at`, `added_by`, `playcount` per track,
  `track_number`, `disc_number`
- Podcast episodes are also surfaced (when a playlist mixes music +
  episodes) with `podcast_uri` and `podcast_name`
- `diff` block — when `trackDiffs` is on, every run after the first
  emits `added`, `removed`, `moved`, `unchanged` counts plus per-track
  detail vs the previous snapshot

### Why scrape Spotify playlists

Spotify's official Playlists endpoint still works for individual
playlists — but it requires OAuth, has aggressive rate limits, and as
of November 2024 Spotify deprecated several adjacent endpoints
(audio-features, related-artists, recommendations, algorithmic and
editorial-playlist data). Editorial-playlist scraping is now the only
reliable way to monitor RapCaviar, Today's Top Hits, mint,
Pop Rising, Viva Latino, and the other 100+ flagship Spotify-owned
playlists at scale.

This actor uses Spotify's `pathfinder` GraphQL endpoint with anonymous
embed-token auth — the same path the public web player uses. No OAuth
app registration, no rate-limit headaches, no Premium required. Pages
through 100+ tracks at a time with `pageSize` 1-200.

The killer feature is the diff layer. Run twice and you get a clean
audit of which tracks were **added**, **removed**, or **moved** (with
their old and new positions) since the last run. Editorial pitching
agencies pay Chartmetric or Spotontrack $80-300/month for this exact
view; this actor does it at $0.01/playlist on whatever cron you want.

### Input

| Field | Default | Description |
|---|---|---|
| `playlists` | required | Array of Spotify playlist IDs (22-char), URIs (`spotify:playlist:<id>`), or `open.spotify.com/playlist/<id>` URLs |
| `trackDiffs` | `true` | If true, persist snapshots and emit added/removed/moved per run vs the previous one. Run twice to see the first diff. |
| `pageSize` | `100` | Tracks per pagination request, 1-200. Lower = more requests but more resilient on giant playlists |

### Output

```json
{
  "uri": "spotify:playlist:37i9dQZF1DXcBWIGoYBM5M",
  "id": "37i9dQZF1DXcBWIGoYBM5M",
  "name": "Today's Top Hits",
  "description": "The hottest 50. Cover: Sabrina Carpenter",
  "followers": 33847291,
  "owner": {"name": "Spotify", "username": "spotify", "uri": "spotify:user:spotify"},
  "image_url": "https://i.scdn.co/image/ab67706f...",
  "total_tracks": 50,
  "is_editorial": true,
  "tracks": [
    {
      "position": 0,
      "uri": "spotify:track:1BxfuPKGuaTgP7aM0Bbdwr",
      "name": "Cruel Summer",
      "duration_ms": 178426,
      "explicit": false,
      "playable": true,
      "playcount": 2847391045,
      "added_at": "2024-08-12T00:00:00Z",
      "artists": [{"name": "Taylor Swift", "uri": "spotify:artist:06HL4z0..."}],
      "album": {"name": "Lover", "cover_url": "https://i.scdn.co/image/..."}
    }
  ],
  "diff": {
    "is_first_snapshot": false,
    "summary": {"added": 3, "removed": 3, "moved": 7, "unchanged": 40},
    "added": [{"position": 12, "uri": "spotify:track:abc...", "name": "..."}],
    "removed": [{"position": 47, "uri": "spotify:track:xyz...", "name": "..."}],
    "moved": [{"prev_position": 8, "new_position": 1, "uri": "...", "name": "..."}]
  }
}
````

### Use cases

**Indie label playlist pitching team** monitoring their pitch list
of 500 editorial + influential third-party playlists. Cron the actor
daily, store the diff. Every morning your team gets a list of every
playlist that swapped tracks — the perfect proxy for which curators
are actively gardening their lists right now versus which are dormant.
Pitch fresh adds first. $5/day for a 500-playlist pitch sheet beats
$129/month Soundcharts and gives you raw JSON for your own CRM.

**A\&R scout tracking what RapCaviar, mint, and Today's Top Hits add.**
Editorial-playlist adds are the strongest leading signal of breakout
artists in 2026 — Spotify's own data shows 30%+ of mainstream charting
acts came through these flagship playlists first. Run this actor on
the 20 flagship Spotify-owned playlists daily ($6/month). When a track
appears in your `diff.added`, fire a webhook to Slack. You're now
ahead of every major-label A\&R who's still refreshing the playlist
pages manually.

**Sync-licensing music supervisor** building mood-and-genre track
shortlists. You don't want generic top hits — you want indie chill,
dark-academia jazz, Y2K nostalgia, etc. Pull every track from 200
mood-curated user playlists (`is_editorial: false`), dedupe by URI,
filter by `playcount` band, and you've got a few thousand
contextually-relevant tracks ranked by reach. Pair with
free-spotify-artist-analytics to enrich each track's artist with
contact info and monthly listeners.

**Music journalist / Substack writer** doing the "what changed on
Today's Top Hits this week" beat. The `diff.added` and `diff.removed`
blocks plus the `moved` deltas are basically a free editorial column
every Monday — the actor saves you 30 minutes of manual playlist
diffing per piece. $0.01 per playlist per run.

### How it compares

| Actor / Tool | Price | Tracklist | Follower Count | Editorial Flag | Cross-run Diff |
|---|---|---|---|---|---|
| **This actor** | **$0.01 / playlist** | full | yes | yes | yes (built-in) |
| `scrapearchitect/spotify-playlists-scraper` (#1 SERP) | per-result | full | yes | no | no |
| `easyapi/spotify-playlists-scraper` | $2 + per-result | basic | yes | no | no |
| Spotify official Web API | free (with OAuth) | full | yes | no (no flag) | no |
| Chartmetric Pro | $140+ / month flat | full | yes | yes | yes |

The cross-run **diff layer** is the differentiator. Most Apify
playlist scrapers give you a snapshot — useful, but to track playlist
churn you'd have to roll your own diff store. This actor does it for
you in `diff_store.py` and emits clean per-run added/removed/moved
records with the snapshot IDs included for audit.

### Pricing

- `$0.01` per playlist returned
- All pricing is **pay-per-event** — you only pay per result. No
  actor-start fee. A playlist with 10 tracks costs the same as a
  playlist with 8,000 tracks: one event.
- Pagination requests are bundled — you're not charged per page.

### Limits and gotchas

- **Anonymous scraping** — no Spotify account or OAuth needed.
- **`pageSize`** capped at 200 by Spotify's GraphQL backend; defaults to
  100 which works reliably even on 10,000-track user playlists.
- **Diff state** is stored in the actor's default key-value store
  scoped to your run. The first run is always `is_first_snapshot:
  true` with empty diff arrays — that's expected. Run twice to see
  the first real diff.
- **Editorial detection** — `is_editorial` is determined by
  `owner.username == "spotify"`. Third-party "editorial-style"
  playlists (e.g. Filtr, Topsify, Digster) are *not* flagged because
  Spotify doesn't own them; if you need to track those, treat them as
  large user playlists.
- **Private / collaborative playlists** require login and will return
  a 404-style error.
- **Region-restricted playlists** still return their tracklist, but
  individual tracks may show `playable: false` for your scrape origin.
- **Cold-start time** is ~5-8s for the first playlist; subsequent
  playlists reuse the embed token and run at ~1-2s each plus 1s per
  100-track page.

### FAQ

**Can I scrape Spotify playlists without OAuth?**
Yes. Anonymous embed-token auth works for any public playlist. No
Spotify account, no developer-app registration, no client credentials.

**How do I track which playlist added or dropped my song?**
Enable `trackDiffs: true` (default), schedule the actor on a daily
or weekly cron, and on each run inspect `diff.added` / `diff.removed`.
For a specific track URI, filter the diff arrays in your downstream
loader.

**Does this work on Spotify-owned editorial playlists?**
Yes — RapCaviar, Today's Top Hits, mint, Viva Latino, Pop Rising,
NMF, all the regional Top 50s, and every other Spotify-owned playlist
work. The `is_editorial` flag will be `true` for those.

**What's the cost to monitor 100 playlists daily?**
$1/day = $30/month. For comparison, Chartmetric Pro starts around
$140/month and Spotontrack starts around $90/month. Below ~13,000
playlist-checks/month this actor is meaningfully cheaper.

**How fresh is the playlist data?**
Live at request time. Spotify updates editorial playlists multiple
times per week (RapCaviar typically refreshes Fridays at 00:00 UTC,
Today's Top Hits Fridays as well). User playlists update whenever the
owner edits.

### Related Actors

- [Free Spotify Artist Analytics](https://apify.com/s-r/free-spotify-artist-analytics) — monthly listeners, world rank, top tracks with playcount
- [Free Spotify Charts Scraper](https://apify.com/s-r/free-spotify-charts) — global Top Tracks / Albums / Artists weekly with rank deltas
- [Free Spotify Podcast Catalog](https://apify.com/s-r/free-spotify-podcast-catalog) — podcast show metadata, episodes, ratings, publisher

# Actor input Schema

## `playlists` (type: `array`):

List of Spotify playlist IDs (22-char), URIs (spotify:playlist:...), or open.spotify.com URLs.

## `trackDiffs` (type: `boolean`):

If true, persist playlist snapshots and emit added/removed/moved per run vs the previous one. Run twice to see the diff.

## `pageSize` (type: `integer`):

Pagination size for tracklist fetch (1-200).

## Actor input object example

```json
{
  "playlists": [
    "37i9dQZF1DXcBWIGoYBM5M",
    "https://open.spotify.com/playlist/37i9dQZEVXbMDoHDwVN2tF"
  ],
  "trackDiffs": true,
  "pageSize": 100
}
```

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

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/free-spotify-playlist-intelligence").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 = { "playlists": ["https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"] }

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

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

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

```

## CLI example

```bash
echo '{
  "playlists": [
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
  ]
}' |
apify call s-r/free-spotify-playlist-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=s-r/free-spotify-playlist-intelligence",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Free Spotify Playlist Intelligence",
        "version": "0.1",
        "x-build-id": "BuOHecUaBOwQKqIpZ"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/s-r~free-spotify-playlist-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-s-r-free-spotify-playlist-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/s-r~free-spotify-playlist-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-s-r-free-spotify-playlist-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/s-r~free-spotify-playlist-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-s-r-free-spotify-playlist-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "playlists"
                ],
                "properties": {
                    "playlists": {
                        "title": "Spotify playlists",
                        "type": "array",
                        "description": "List of Spotify playlist IDs (22-char), URIs (spotify:playlist:...), or open.spotify.com URLs.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "trackDiffs": {
                        "title": "Track diffs across runs",
                        "type": "boolean",
                        "description": "If true, persist playlist snapshots and emit added/removed/moved per run vs the previous one. Run twice to see the diff.",
                        "default": true
                    },
                    "pageSize": {
                        "title": "Tracks per page",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Pagination size for tracklist fetch (1-200).",
                        "default": 100
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
