# Spotify Curator & Playlist Owner Profiler (`fanndev/spotify-curator-profiler`) Actor

Find the curators behind Spotify playlists in any niche and profile them: how many playlists they run, total follower reach, the artists they favour, how underground their picks are and whether they are still active. No Spotify account or API key.

- **URL**: https://apify.com/fanndev/spotify-curator-profiler.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 results

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 Curator & Playlist Owner Profiler

Find out **who is curating** a niche on Spotify, how much reach they have, and
what their taste actually looks like — the artists they favour, how underground
their picks are, how current their catalogue is, and whether they are still
active.

Built for artist teams pitching for playlist placement, for brands profiling
music influencers, and for market researchers mapping a scene.

No Spotify account, no API key, no browser.

***

### What you get per curator

| Field | Notes |
| --- | --- |
| `ownerName`, `ownerId`, `ownerUrl`, `ownerAvatar` | Who they are and where to find them |
| **`totalFollowers`** | Reach summed across their playlists found |
| `playlistsFound`, `biggestPlaylistName`, `totalTracksCurated` | Scale of what they run |
| **`topArtistNames`**, `topArtists`, `distinctArtists` | Who they actually play |
| **`undergroundScore`** | 0–1 from median play count — discovery curator or hits curator |
| `medianPlaycount`, `maxPlaycount` | The raw numbers behind it |
| `medianReleaseYear`, `catalogueSpreadYears` | New-music curator vs retrospective |
| `explicitShare` | Whether the playlist is brand-safe |
| **`lastUpdated`** | Still active, or abandoned two years ago |

Plus one **`PLAYLIST`** row per playlist — including its **description**, which
is where curators usually put their submission instructions and contact email.

***

### Quick start

```json
{
  "keywords": ["indie folk", "lofi study", "afrobeats 2026"],
  "minFollowers": 5000,
  "trackSampleSize": 50,
  "exportFormats": ["csv"]
}
```

Real output from a two-keyword run:

```
Lofi Girl          1 playlist   616,480 followers   underground 0.77   median yr 2021
mixstarrs          1 playlist   393,618 followers   underground 0.00   median yr 2020
Etymology Lofi     1 playlist   187,712 followers   underground 0.99   median yr 2022
```

Three curators in the same niche with completely different pitching profiles.

***

### Read this before you rely on it

**Spotify has closed off user profiles to anonymous clients.** Its profile
service answers `403 RBAC: access denied` even with a valid client-token, and a
user page renders nothing but a display name without a login. So there is **no
way to list a given user's public playlists, or who they follow** — that door
is shut, and any tool claiming otherwise is either logged in as someone or
guessing.

This actor works the other way round: it finds the **playlists**, which are
fully public and name their owner in full, and builds the curator profile from
those. That means:

- `playlistsFound` is what **this run discovered**, not the curator's complete
  catalogue. More keywords find more of their work.
- A curator only appears if at least one of their playlists surfaced in search.

***

### Coverage comes from keywords, not page size

Spotify's search returns **at most 30 mixed-type results** per query — tracks,
artists, playlists and podcasts together, typically 15–20 playlists — and it
**ignores every paging parameter**. Asking for more is not an error; it simply
changes nothing.

So breadth comes from running more, narrower keywords: `"indie folk"`,
`"indie folk 2026"`, `"folk acoustic chill"` will between them surface far more
curators than any single query can. Results are also **geo-biased by exit IP**,
so set the proxy country to the market you care about when profiling a local
scene.

**`includeEditorialPlaylists` is off by default** because Spotify's own account
owns the biggest playlist in nearly every niche, and leaving it in makes
"Spotify" top every ranking — true, but useless when you are looking for
independent curators to approach.

***

### Cost

One request per keyword, plus **one request per playlist** — which returns the
follower count and the track sample together, so taste profiling is free. Two
keywords yielding 13 playlists is 16 requests.

***

### Limits worth knowing

- **Follower counts are per playlist, not per curator.** Spotify publishes no
  profile-level follower number to anonymous clients, so `totalFollowers` is a
  sum across playlists found and one person following two of their playlists
  is counted twice.
- **`undergroundScore` is derived, not a Spotify field.** It is a transform of
  the median play count and is meant for comparing curators against each other,
  not as an absolute rating.
- **Playlists can hold podcast episodes and local files.** Those are skipped in
  the taste sample rather than counted as tracks.
- **A playlist that has been deleted or made private** produces an `ERROR` row;
  Spotify does not distinguish the two from outside.

***

### Output

Every run writes to the Apify dataset, with curators sorted by reach. Set
`exportFormats` to also drop a ready-made `spotify-curators.csv`, `.xlsx`,
`.json` or `.ndjson` into the run's key-value store.

See [CRAWLING_METHOD.md](CRAWLING_METHOD.md) for how the data is obtained.

# Actor input Schema

## `keywords` (type: `array`):

Genres, moods or scenes to find curators in - 'indie folk', 'lofi study', 'afrobeats 2026', 'dangdut koplo'. Spotify returns at most 30 mixed results per keyword and ignores paging entirely, so coverage comes from using more keywords, not from asking for more per keyword. Results are also biased by the exit IP's country.

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

Specific playlists whose owners you want profiled. Share links, spotify:playlist: URIs and bare playlist ids all work.

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

The same playlist links in the request-list format, for callers that already keep one.

## `trackSampleSize` (type: `integer`):

How many tracks to read from each playlist in order to describe the curator's taste. The sample costs nothing extra - the tracks arrive in the same request as the playlist's follower count. Set it to 0 to skip taste profiling and keep only reach numbers.

## `maxPlaylistsPerKeyword` (type: `integer`):

Cap on how many of each keyword's playlist results to profile. Spotify never returns more than 30 results of all types combined, so values above roughly 20 rarely change anything.

## `maxPlaylists` (type: `integer`):

Overall ceiling across every keyword and URL, after de-duplication. Each playlist costs one request.

## `minFollowers` (type: `integer`):

Skip playlists below this follower count. Useful for filtering out the long tail of personal playlists when you are looking for curators worth pitching to.

## `includeEditorialPlaylists` (type: `boolean`):

Off by default. Spotify's editorial account owns the largest playlists in almost every niche, so leaving it in means 'Spotify' tops every ranking - true, but useless if you are looking for independent curators to approach. Turn it on when you want the editorial benchmark alongside them.

## `emitPlaylistRecords` (type: `boolean`):

Write each profiled playlist as its own PLAYLIST row alongside the CURATOR rows: name, description, followers, track count, last update and owner.

## `exportFormats` (type: `array`):

Besides the dataset, write ready-made files into this run's key-value store.

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

Off by default and genuinely optional: neither endpoint has a WAF or an IP block. It does change one thing - search results are geo-biased, so an exit IP in the market you care about surfaces local curators that a default one will not.

## Actor input object example

```json
{
  "keywords": [
    "indie folk",
    "lofi study"
  ],
  "trackSampleSize": 50,
  "maxPlaylistsPerKeyword": 15,
  "maxPlaylists": 200,
  "minFollowers": 0,
  "includeEditorialPlaylists": false,
  "emitPlaylistRecords": true,
  "exportFormats": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per curator, the playlists behind each profile and any error records from this run.

# 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 = {
    "keywords": [
        "indie folk",
        "lofi study"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/spotify-curator-profiler").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 = { "keywords": [
        "indie folk",
        "lofi study",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fanndev/spotify-curator-profiler").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 '{
  "keywords": [
    "indie folk",
    "lofi study"
  ]
}' |
apify call fanndev/spotify-curator-profiler --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/spotify-curator-profiler"
        }
    }
}
```

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/puFUVpti4JIgBQ3n2/builds/arY0vtttyr9aaKtNi/openapi.json
