# Spotify Playlist Search and Metadata Scraper (`automation-lab/spotify-playlist-search-scraper`) Actor

Search public Spotify playlists by keyword or enrich playlist URLs with owners, artwork, track counts, and nested public track metadata.

- **URL**: https://apify.com/automation-lab/spotify-playlist-search-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 50.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/platform/actors/running/actors-in-store#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

## Spotify Playlist Search and Metadata Scraper

Search Spotify playlists by keyword, enrich public playlist URLs, and export clean playlist metadata with nested track records.

Use this Actor for playlist discovery, curator research, music programming, catalog analysis, and recurring public-data snapshots. It does not require Spotify API credentials or a logged-in Spotify account.

### What does this Spotify playlist scraper do?

The Actor searches Spotify's public playlist catalog and turns each result into one integration-ready dataset row.

For every accepted playlist it can return:

- Spotify playlist ID, URI, and public URL;
- playlist name, description, owner, and cover image;
- the search query that found the playlist;
- the number of tracks exposed by Spotify's public embed;
- nested track IDs, titles, artist text, duration, explicit status, playability, and preview URL;
- an ISO extraction timestamp for snapshots and comparisons.

You can also skip search and supply known public playlist URLs. Both routes use the same detail enrichment and output contract.

### Who is it for?

#### Music researchers

Discover playlists around genres, moods, activities, artists, or cultural moments and export their public track makeup.

#### Playlist curators and labels

Map public playlists, identify owner names, and inspect which tracks appear in relevant search results.

#### Marketing and audience teams

Build repeatable datasets for campaign research without copying Spotify pages manually.

#### Data engineers

Feed normalized playlist rows into Sheets, databases, notebooks, BI tools, webhooks, or scheduled Apify workflows.

### Why use this dedicated Actor?

The broader [Spotify Scraper](https://apify.com/automation-lab/spotify-scraper) handles several Spotify entity types. This Actor is intentionally focused on playlist discovery: it searches only playlists, deduplicates them across queries and URLs, and enriches each discovered playlist with its public track list.

It uses lightweight HTTP requests rather than a browser. That keeps runs fast, memory-efficient, and economical while preserving the buyer workflow.

### What Spotify playlist data can I extract?

| Field | Meaning |
| --- | --- |
| `playlistId` | Stable Spotify playlist ID |
| `uri` | `spotify:playlist:` URI |
| `url` | Public `open.spotify.com` playlist URL |
| `name` | Playlist title |
| `description` | Public search description, or `null` when unavailable |
| `owner` | Public owner display name |
| `imageUrl` | Playlist cover image URL |
| `trackCount` | Tracks exposed by the public embed at extraction time |
| `tracks` | Nested public track records when `includeTracks` is enabled |
| `searchQuery` | Query that discovered the playlist, or `null` for URL input |
| `source` | `search` or `url` |
| `scrapedAt` | ISO 8601 extraction timestamp |

Each nested track includes position, Spotify ID/URI/URL, title, artist text, duration, explicit status, playability, and an optional audio preview URL.

Spotify does not expose follower/save counts or a reliable playlist last-updated timestamp on the verified anonymous search and embed surfaces. Those fields are not invented.

### How to search Spotify playlists

1. Open the Actor input page.
2. Add one or more values to **Playlist search queries**.
3. Set **Maximum playlists** for the combined run.
4. Keep **Include track records** enabled when you need track-level detail.
5. Click **Start**.
6. Open the default dataset to export JSON, CSV, Excel, XML, RSS, or another supported format.

A good first input is:

```json
{
  "queries": ["indie workout"],
  "maxItems": 10,
  "includeTracks": true
}
```

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `queries` | string array | `["indie workout"]` | Playlist keywords. Up to 20 queries. |
| `playlistUrls` | string array | empty | Public Spotify playlist URLs or `spotify:playlist:` URIs. |
| `includeTracks` | boolean | `true` | Include nested public track records. |
| `maxItems` | integer | `20` | Maximum unique playlists across every input route; range 1–500. |

Provide `queries`, `playlistUrls`, or both. Duplicate playlist IDs are emitted once. URL inputs are processed first and count toward `maxItems`.

Malformed arrays, unsupported URLs, and out-of-range limits fail clearly instead of silently changing scope.

### Output example

A real run for `indie workout` produces records shaped like this:

```json
{
  "type": "playlist",
  "playlistId": "37i9dQZF1DX35oM5SPECmN",
  "uri": "spotify:playlist:37i9dQZF1DX35oM5SPECmN",
  "url": "https://open.spotify.com/playlist/37i9dQZF1DX35oM5SPECmN",
  "name": "Run Wild",
  "description": null,
  "owner": "Spotify",
  "imageUrl": "https://image-cdn-fa.spotifycdn.com/image/...",
  "trackCount": 75,
  "tracks": [
    {
      "position": 1,
      "trackId": "5w6B0sAH7XauCvMOAtplQj",
      "uri": "spotify:track:5w6B0sAH7XauCvMOAtplQj",
      "url": "https://open.spotify.com/track/5w6B0sAH7XauCvMOAtplQj",
      "name": "Fire",
      "artists": "Barns Courtney",
      "durationMs": 197520,
      "explicit": false,
      "playable": true,
      "previewUrl": "https://p.scdn.co/mp3-preview/..."
    }
  ],
  "searchQuery": "indie workout",
  "source": "search",
  "scrapedAt": "2026-07-29T04:35:00.000Z"
}
```

### How much does it cost to search Spotify playlists?

This is a pay-per-event Actor. A run has a **$0.00005 start charge** and each saved playlist has a tiered item charge. On the BRONZE tier, one playlist costs **$0.002068**; every nested track in that playlist is included with no separate event charge.

Active item prices decrease by Apify customer tier:

| Tier | Charge per saved playlist |
| --- | ---: |
| FREE | $0.0023782 |
| BRONZE | $0.002068 |
| SILVER | $0.001613 |
| GOLD | $0.0012408 |
| PLATINUM | $0.0008272 |
| DIAMOND | $0.00057904 |

For example, a BRONZE run that saves multiple playlists receives one $0.00005 start event plus one $0.002068 item event for each saved playlist. The Console shows the exact maximum charge before a run. Public-data availability may affect how many rows are produced; only saved playlist rows receive the item event.

### Tips for useful playlist research

- Use buyer-language queries such as `indie workout`, `coding focus`, or `afrobeats party`.
- Split very different intents into separate runs when you want cleaner snapshot comparisons.
- Set `includeTracks` to `false` if you only need playlist-level discovery fields.
- Schedule the same input and compare playlist IDs or nested track IDs downstream.
- Store `scrapedAt` with each export so later comparisons remain auditable.
- Start with a small `maxItems`, inspect relevance, then scale the same query.

### Limitations and freshness

Spotify controls search ranking and the public web-player response. Results can vary by time and source behavior.

The public embed may expose fewer tracks than a private or logged-in Spotify client. Private, deleted, unavailable, or region-restricted playlists may fail enrichment.

This Actor does not:

- log in to Spotify;
- access private or collaborative-member data;
- provide listener identities;
- fabricate follower/save counts;
- infer a playlist's last-update timestamp;
- download full audio files;
- guarantee a fixed ranking or complete global catalog.

A persisted web query or embedded state format can change. When Spotify returns an unrecognized shape, the run reports an error or skips the affected detail with a warning rather than emitting fabricated data.

### Recurring workflows and integrations

#### Playlist discovery dashboard

Schedule daily or weekly searches, export the dataset to a database, and chart new playlist IDs by query and owner.

#### Track-placement research

Flatten the nested `tracks` array in a data warehouse to compare which public playlists contain a track or artist.

#### Curator list building

Group results by `owner`, retain the Spotify playlist URL, and prioritize relevant public playlists for manual research.

#### Catalog monitoring

Run known `playlistUrls` on a schedule and compare track IDs with the previous dataset. Apify schedules and webhooks can trigger the downstream diff automatically.

#### Spreadsheet export

Download the default dataset as CSV or Excel for playlist-level fields. Use JSON when you need the full nested track array.

### Run through the Apify API with cURL

Replace `YOUR_APIFY_TOKEN` with your token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~spotify-playlist-search-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": ["jazz focus"],
    "maxItems": 10,
    "includeTracks": true
  }'
```

To wait for results in one request, use the synchronous dataset endpoint:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~spotify-playlist-search-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["jazz focus"],"maxItems":5,"includeTracks":true}'
```

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/spotify-playlist-search-scraper').call({
  queries: ['instrumental focus', 'coding focus'],
  maxItems: 25,
  includeTracks: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/spotify-playlist-search-scraper').call(run_input={
    'playlistUrls': ['https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M'],
    'maxItems': 1,
    'includeTracks': True,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI agents

Add the Actor to Claude Code through Apify's MCP server:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/spotify-playlist-search-scraper"
```

#### Claude Desktop, Cursor, and VS Code setup

Claude Desktop, Cursor, and VS Code can use this MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/spotify-playlist-search-scraper"
    }
  }
}
```

Example prompts:

- “Search Spotify for public deep-focus playlists and return the owner, URL, and track count.”
- “Extract the public tracks from this Spotify playlist URL and summarize artists represented.”
- “Run the same curator-research input and save the dataset for comparison with next week's run.”

### Responsible use and legality

Use the Actor only for lawful purposes and public data you are authorized to process. Review Spotify's terms and applicable privacy, copyright, database, and marketing laws for your jurisdiction and use case.

Do not use output to harass users, evade platform controls, claim private access, or redistribute audio unlawfully. Playlist owner names are public display data; minimize retention and sharing when personal data is not necessary for your purpose.

The Actor is an independent data tool and is not affiliated with or endorsed by Spotify.

### Troubleshooting

#### Why did a public playlist URL produce no row?

Confirm that it uses `https://open.spotify.com/playlist/<id>` or `spotify:playlist:<id>` and opens without login. Private, deleted, malformed, and unavailable playlists cannot be enriched.

#### Why are follower or save counts missing?

The verified anonymous public search and embed surfaces do not expose reliable follower/save counts. The Actor deliberately omits unsupported values.

#### Why is the description null?

Spotify exposes descriptions in playlist search results but not consistently in direct embeds. A URL-only record can therefore have `description: null`.

#### Why did search fail after working before?

Spotify can change its anonymous web-player query. Inspect the run log for a response-shape or HTTP error. Retry transient failures later; repeated shape errors require an Actor update rather than a proxy setting.

#### Does the Actor use a proxy?

No automatic proxy or browser fallback is enabled. The verified route uses direct public HTTP requests, avoiding hidden residential-proxy cost.

### Related Automation Lab Actors

- [Spotify Scraper](https://apify.com/automation-lab/spotify-scraper) — search or extract artists, albums, tracks, and playlists in a broader multi-entity workflow.
- [Spotify Track Play Count Scraper](https://apify.com/automation-lab/spotify-track-play-count-scraper) — focus on Spotify track play-count research.
- [Spotify Podcast Charts Scraper](https://apify.com/automation-lab/spotify-podcast-charts-scraper) — collect public Spotify podcast chart data.

### FAQ

#### Do I need Spotify API credentials?

No. The Actor uses Spotify's anonymous public web-player surfaces.

#### Can I search more than one keyword?

Yes. Add up to 20 queries. Results are deduplicated by Spotify playlist ID across the whole run.

#### Are track rows charged separately?

No. Tracks are nested in the charged playlist row and have no separate event charge.

#### Can I monitor playlist changes?

You can schedule repeat URL or search inputs and compare datasets downstream. The Actor returns snapshots; it does not maintain a private historical database or send its own alerts.

#### Can I scrape private playlists?

No. Only public playlists available through Spotify's anonymous surfaces are supported.

#### What happens at `maxItems`?

The Actor stops accepting new unique playlists. It does not silently raise the limit or charge beyond the saved records.

# Actor input Schema

## `queries` (type: `array`):

Keywords to search in Spotify's public playlist catalog, such as indie workout or jazz focus.

## `playlistUrls` (type: `array`):

Optional public playlist URLs or spotify:playlist URIs to enrich directly.

## `includeTracks` (type: `boolean`):

Include the publicly exposed track list and track metadata inside each playlist record.

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

Maximum unique playlist records across all queries and URLs.

## Actor input object example

```json
{
  "queries": [
    "indie workout"
  ],
  "playlistUrls": [
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
  ],
  "includeTracks": true,
  "maxItems": 10
}
```

# Actor output Schema

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

Dataset containing playlist metadata and nested track records.

# 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 = {
    "queries": [
        "indie workout"
    ],
    "playlistUrls": [
        "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
    ],
    "includeTracks": true,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/spotify-playlist-search-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 = {
    "queries": ["indie workout"],
    "playlistUrls": ["https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"],
    "includeTracks": True,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/spotify-playlist-search-scraper").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 '{
  "queries": [
    "indie workout"
  ],
  "playlistUrls": [
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
  ],
  "includeTracks": true,
  "maxItems": 10
}' |
apify call automation-lab/spotify-playlist-search-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/Q6AzkjDC8DXeoJl0c/builds/wVuOSWlJkADGaB5pw/openapi.json
