# Spotify Scraper – Play Counts & Monitoring (`scrapingmonkey/spotify-scraper`) Actor

Search Spotify or scrape public artists, tracks, albums, playlists, podcasts, episodes, and user profiles. Extract play counts, monthly listeners, credits, full child collections, and monitor changes—without a Spotify API key or login. Independent tool; not affiliated with Spotify.

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

## Pricing

from $0.30 / 1,000 search 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/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 Analytics Scraper - Play Counts, Monthly Listeners and Playlist Monitoring

Extract public Spotify artists, tracks, albums, playlists, podcasts, episodes, and users into analysis-ready datasets, including metrics and relationships that are not present in basic search cards.

- Search seven public entity types with independent limits per keyword and type
- Collect artist monthly listeners, follower counts, world rank, top cities, biography, top tracks, and discography
- Extract track play counts, ISRC, market availability, album context, and grouped credits
- Paginate album tracks, playlist tracks, artist releases, public user playlists, and podcast episodes
- Extract public user followers/following, verification, profile flags, recently played artists, and large playlist libraries
- Monitor metric changes, new releases, playlist additions/removals/reordering, and new episodes across scheduled runs
- Accept Spotify URLs, `spotify:type:id` URIs, bare IDs, and mixed entity batches
- No Spotify Developer API key, OAuth application, login, cookies, or user-supplied proxy configuration required
- Export to JSON, CSV, Excel, XML, or access results through the Apify API

### What can you do with this Actor?

| Mode | Input | Output | Best for |
| --- | --- | --- | --- |
| `search` | Keywords plus selected entity types | Artist, track, album, playlist, show, episode, and user rows | Discovery, catalog research, playlist prospecting |
| `details` | Public Spotify URLs, URIs, or IDs | Rich entity rows with optional flat child rows | Music analytics, metadata enrichment, catalog exports |
| `monitor` | The same public entity inputs plus a stable `monitorKey` | Initialized, added, removed, and modified change rows | Scheduled artist, playlist, release, and podcast tracking |

One mode runs at a time. IDs found in `search` can be sent directly to `details` or `monitor`. In `flat` output, parent entities and their tracks, releases, related artists, public user playlists, recently played artists, or episodes become separate dataset rows with `parentType`, `parentId`, `relationType`, `relationId`, and `position`.

### Quick start

1. Open the Actor and click **Try for free**.
2. Keep `search` selected and enter one or more search terms.
3. Choose entity types and set `maxResults`.
4. Click **Start**.
5. Preview the dataset or download it in your preferred format.

The default input searches `indie pop` and returns up to 50 artists, 50 tracks, and 50 playlists.

### Input examples

#### Search artists, tracks, and playlists

```json
{
  "mode": "search",
  "searchTerms": ["indie pop", "workout music"],
  "entityTypes": ["artist", "track", "playlist"],
  "maxResults": 20,
  "market": "US",
  "locale": "en-US",
  "includeDetails": false,
  "maxConcurrency": 5
}
```

`maxResults` applies separately to every search term and selected entity type. The example can therefore return up to 120 primary rows: 2 terms × 3 types × 20 results.

#### Rich details from mixed Spotify references

```json
{
  "mode": "details",
  "spotifyIds": [
    "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
    "spotify:track:53iuhJlwXhSER5J2IYYv1W",
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M",
    "https://open.spotify.com/show/1VXcH8QHkjRcTCEd88U3ti",
    "https://open.spotify.com/user/spotify"
  ],
  "maxResults": 100,
  "market": "US",
  "includeTracks": true,
  "includeDiscography": true,
  "includeRelatedArtists": true,
  "includeCredits": true,
  "includeEpisodes": true,
  "includeUserPlaylists": true,
  "includeUserArtists": true,
  "maxConcurrency": 5,
  "outputMode": "flat"
}
```

#### Monitor artist metrics and playlist contents

```json
{
  "mode": "monitor",
  "spotifyIds": [
    "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
    "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"
  ],
  "monitorKey": "music-roster-us",
  "maxResults": 500,
  "market": "US",
  "outputMode": "flat",
  "emitOnlyChanges": true
}
```

The first run emits an `initialized` change and stores a snapshot in a persistent named key-value store. Later runs using the same `monitorKey` emit `added`, `removed`, and `modified` changes.

### Complete output examples

All entity serializers use fixed top-level key sets. Missing source values are represented by `null`, `[]`, `{}`, `false`, or `0`; entity fields are not conditionally omitted. Search rows use the same shapes as detail rows, with unavailable enrichment fields left empty. Flat child rows use the appropriate entity shape and populate the relationship fields.

#### Complete `episode` output - 34 top-level fields

```json
{
  "recordType": "episode",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": "show",
  "parentId": "1VXcH8QHkjRcTCEd88U3ti",
  "relationType": "showEpisode",
  "relationId": "2XiNimTxVs3P9oC5IAb0eB",
  "position": 1,
  "id": "2XiNimTxVs3P9oC5IAb0eB",
  "uri": "spotify:episode:2XiNimTxVs3P9oC5IAb0eB",
  "url": "https://open.spotify.com/episode/2XiNimTxVs3P9oC5IAb0eB",
  "name": "Why I’m obsessed with health wearables",
  "market": "US",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "description": "Episode description.",
  "htmlDescription": "<p>Episode description.</p>",
  "durationMs": 2925531,
  "releaseDate": "2026-08-07T10:00:00Z",
  "releaseDatePrecision": "MINUTE",
  "explicit": false,
  "contentRating": "NONE",
  "mediaTypes": ["AUDIO"],
  "playable": true,
  "playabilityReason": "PLAYABLE",
  "previewUrl": "https://podz-content.spotifycdn.com/audio/clips/example.mp3",
  "images": [
    {
      "url": "https://i.scdn.co/image/episode-cover",
      "width": 640,
      "height": 640
    }
  ],
  "show": {
    "id": "1VXcH8QHkjRcTCEd88U3ti",
    "uri": "spotify:show:1VXcH8QHkjRcTCEd88U3ti",
    "url": "https://open.spotify.com/show/1VXcH8QHkjRcTCEd88U3ti",
    "name": "TED Talks Daily",
    "publisher": "TED",
    "images": [
      {
        "url": "https://i.scdn.co/image/show-cover",
        "width": 640,
        "height": 640
      }
    ]
  },
  "restrictions": {
    "reason": null,
    "paywallContent": false
  },
  "accessInfo": {
    "isMember": false,
    "title": "Support this show",
    "body": "Some content is only available to subscribers.",
    "actionText": "Get access",
    "url": "https://content-access.spotify.com/example",
    "signifier": "Subscriber"
  },
  "gatedRelations": [
    {
      "badges": ["Extras"],
      "summaryForUserWithAccess": "You have access to extras.",
      "summaryForUserWithoutAccess": "Extras for subscribers.",
      "relatedUri": "spotify:episode:relatedEpisodeId"
    }
  ],
  "transcripts": [
    {
      "language": "en-US",
      "uri": "spotify:transcript:transcriptId",
      "url": "https://open.spotify.com/transcript/transcriptId"
    }
  ],
  "segments": [
    {
      "startMs": 0,
      "endMs": 60000,
      "title": "Introduction",
      "type": "CHAPTER"
    }
  ],
  "audioUrls": ["https://p.scdn.co/mp3-preview/episode-preview.mp3"]
}
```

The Actor returns public transcript metadata when Spotify exposes it; it does not download or reproduce full transcript or audio content.

#### Complete `user` output - 35 top-level fields

```json
{
  "recordType": "user",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": null,
  "parentId": null,
  "relationType": null,
  "relationId": null,
  "position": null,
  "id": "spotify",
  "uri": "spotify:user:spotify",
  "url": "https://open.spotify.com/user/spotify",
  "name": "Spotify",
  "market": "PH",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "displayName": "Spotify",
  "username": "spotify",
  "socialHandle": null,
  "followers": 12128619,
  "followingCount": 327,
  "verified": true,
  "reportAbuseDisabled": true,
  "hasSpotifyName": true,
  "hasSpotifyImage": true,
  "profileColor": 16085920,
  "allowFollows": true,
  "showFollows": true,
  "accountId": "y84kXNyOqb",
  "images": [
    {
      "url": "https://i.scdn.co/image/user-avatar",
      "width": 300,
      "height": 300
    }
  ],
  "publicPlaylistCount": 1519,
  "publicPlaylistsReturned": 1,
  "recentlyPlayedArtistCount": 0,
  "externalUrls": {
    "spotify": "https://open.spotify.com/user/spotify"
  },
  "playlists": [
    {
      "id": "userPlaylistId",
      "uri": "spotify:playlist:userPlaylistId",
      "url": "https://open.spotify.com/playlist/userPlaylistId",
      "name": "Public playlist",
      "description": "Playlist description",
      "owner": {
        "id": "spotify",
        "uri": "spotify:user:spotify",
        "url": "https://open.spotify.com/user/spotify",
        "name": "Spotify",
        "username": "spotify",
        "images": []
      },
      "images": [
        {
          "url": "https://i.scdn.co/image/user-playlist",
          "width": 640,
          "height": 640
        }
      ],
      "totalTracks": null,
      "followers": 34324513
    }
  ],
  "recentlyPlayedArtists": []
}
```

#### Complete `change` output - 15 top-level fields

```json
{
  "recordType": "change",
  "sourceMode": "monitor",
  "monitorKey": "music-roster-us",
  "changeType": "modified",
  "entityType": "artist",
  "entityId": "06HL4z0CvFAxyc27GXpf02",
  "childType": null,
  "childId": null,
  "changedFields": ["monthlyListeners"],
  "before": {
    "recordKey": "artist|06HL4z0CvFAxyc27GXpf02||||",
    "recordType": "artist",
    "id": "06HL4z0CvFAxyc27GXpf02",
    "parentType": null,
    "parentId": null,
    "relationType": null,
    "relationId": null,
    "values": [
      {
        "field": "monthlyListeners",
        "value": 100800000
      }
    ]
  },
  "after": {
    "recordKey": "artist|06HL4z0CvFAxyc27GXpf02||||",
    "recordType": "artist",
    "id": "06HL4z0CvFAxyc27GXpf02",
    "parentType": null,
    "parentId": null,
    "relationType": null,
    "relationId": null,
    "values": [
      {
        "field": "monthlyListeners",
        "value": 100887660
      }
    ]
  },
  "sourceUrl": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
  "market": "US",
  "locale": "en-US",
  "detectedAt": "2026-08-08T01:00:00Z"
}
```

`changeType` is `initialized`, `added`, `removed`, or `modified`. For child changes, `childType` and `childId` identify the release, track, related artist, or episode. Each side contains fixed identity keys and a `values` array with complete `{field, value}` objects for the fields that changed.

#### Complete `error` output - 13 top-level fields

```json
{
  "recordType": "error",
  "sourceMode": "details",
  "input": "spotify:track:not-found",
  "entityType": "track",
  "entityId": "not-found",
  "sourceUrl": "https://open.spotify.com/track/not-found",
  "market": "US",
  "locale": "en-US",
  "errorType": "not_found",
  "errorMessage": "Spotify track not-found was not found or is unavailable",
  "httpStatus": 404,
  "retryable": false,
  "scrapedAt": "2026-08-08T01:00:00Z"
}
```

#### Complete `playlist` output - 29 top-level fields

```json
{
  "recordType": "playlist",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": null,
  "parentId": null,
  "relationType": null,
  "relationId": null,
  "position": null,
  "id": "1ew3szJaVPZ9TdEU3Kbl4d",
  "uri": "spotify:playlist:1ew3szJaVPZ9TdEU3Kbl4d",
  "url": "https://open.spotify.com/playlist/1ew3szJaVPZ9TdEU3Kbl4d",
  "name": "Eminem All Songs",
  "market": "US",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "description": "A public playlist description.",
  "owner": {
    "id": "dionrozeveld",
    "uri": "spotify:user:dionrozeveld",
    "url": "https://open.spotify.com/user/dionrozeveld",
    "name": "Dion",
    "username": "dionrozeveld",
    "images": [
      {
        "url": "https://i.scdn.co/image/playlist-owner",
        "width": 300,
        "height": 300
      }
    ]
  },
  "followers": 86695,
  "following": false,
  "public": true,
  "collaborative": false,
  "snapshotId": "MTIzLGFiYw==",
  "revisionId": "AAAAZJWwnb4CCsehIM62nMOOhtUbMgEj",
  "totalTracks": 463,
  "images": [
    {
      "url": "https://i.scdn.co/image/playlist-cover",
      "width": 640,
      "height": 640
    }
  ],
  "members": [
    {
      "id": "collaborator",
      "uri": "spotify:user:collaborator",
      "url": "https://open.spotify.com/user/collaborator",
      "name": "Collaborator",
      "username": "collaborator",
      "images": []
    }
  ],
  "capabilities": {
    "canAbuseReport": true,
    "canAdministratePermissions": false,
    "canCancelMembership": false,
    "canEditItems": false,
    "canMixPlaylist": true,
    "canView": true
  },
  "format": {
    "type": null,
    "attributes": [
      {
        "name": "example",
        "value": "value"
      }
    ]
  },
  "tracks": [
    {
      "id": "7lQ8MOhq6IN2w8EYcFNSUk",
      "uri": "spotify:track:7lQ8MOhq6IN2w8EYcFNSUk",
      "url": "https://open.spotify.com/track/7lQ8MOhq6IN2w8EYcFNSUk",
      "name": "Without Me",
      "durationMs": 290320,
      "explicit": true,
      "playable": true,
      "playCount": 2400000000,
      "trackNumber": 10,
      "discNumber": 1,
      "artists": [
        {
          "id": "7dGJo4pcD2V6oG8kP0tJRR",
          "uri": "spotify:artist:7dGJo4pcD2V6oG8kP0tJRR",
          "url": "https://open.spotify.com/artist/7dGJo4pcD2V6oG8kP0tJRR",
          "name": "Eminem"
        }
      ],
      "album": {
        "id": "2cWBwpqMsDJC1ZUwz813lo",
        "uri": "spotify:album:2cWBwpqMsDJC1ZUwz813lo",
        "url": "https://open.spotify.com/album/2cWBwpqMsDJC1ZUwz813lo",
        "name": "The Eminem Show",
        "albumType": "ALBUM",
        "releaseDate": "2002-05-26",
        "releaseDatePrecision": "DAY",
        "totalTracks": 20,
        "images": [
          {
            "url": "https://i.scdn.co/image/playlist-track-album",
            "width": 640,
            "height": 640
          }
        ],
        "artists": [
          {
            "id": "7dGJo4pcD2V6oG8kP0tJRR",
            "uri": "spotify:artist:7dGJo4pcD2V6oG8kP0tJRR",
            "url": "https://open.spotify.com/artist/7dGJo4pcD2V6oG8kP0tJRR",
            "name": "Eminem"
          }
        ]
      },
      "images": [
        {
          "url": "https://i.scdn.co/image/playlist-track",
          "width": 640,
          "height": 640
        }
      ],
      "position": 1,
      "uid": "playlist-item-uid",
      "addedAt": "2026-01-01T00:00:00Z",
      "addedBy": {
        "id": "dionrozeveld",
        "uri": "spotify:user:dionrozeveld",
        "url": "https://open.spotify.com/user/dionrozeveld",
        "name": "Dion",
        "username": "dionrozeveld",
        "images": []
      },
      "attributes": {
        "isLocal": false,
        "isEpisode": false
      }
    }
  ]
}
```

#### Complete `show` output - 37 top-level fields

```json
{
  "recordType": "show",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": null,
  "parentId": null,
  "relationType": null,
  "relationId": null,
  "position": null,
  "id": "1VXcH8QHkjRcTCEd88U3ti",
  "uri": "spotify:show:1VXcH8QHkjRcTCEd88U3ti",
  "url": "https://open.spotify.com/show/1VXcH8QHkjRcTCEd88U3ti",
  "name": "TED Talks Daily",
  "market": "US",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "publisher": "TED",
  "description": "Ideas worth spreading, every weekday.",
  "htmlDescription": "<p>Ideas worth spreading, every weekday.</p>",
  "explicit": false,
  "mediaType": "AUDIO",
  "contentType": "CONTENT_TYPE_PODCAST",
  "consumptionOrder": "EPISODIC",
  "languages": ["en"],
  "availableMarkets": ["US", "GB"],
  "copyrights": [
    {
      "text": "© TED",
      "type": "C"
    }
  ],
  "images": [
    {
      "url": "https://i.scdn.co/image/show-cover",
      "width": 640,
      "height": 640
    }
  ],
  "totalEpisodes": 2774,
  "rating": 4.575455838613745,
  "ratingCount": 7733,
  "topics": [
    {
      "title": "Education",
      "uri": "spotify:genre:education"
    }
  ],
  "showTypes": ["PODCAST"],
  "trailer": {
    "id": "trailerEpisodeId",
    "uri": "spotify:episode:trailerEpisodeId",
    "url": "https://open.spotify.com/episode/trailerEpisodeId",
    "name": "Show trailer",
    "durationMs": 60000,
    "releaseDate": "2026-01-01T00:00:00Z",
    "explicit": false,
    "playable": true,
    "show": {
      "id": "1VXcH8QHkjRcTCEd88U3ti",
      "uri": "spotify:show:1VXcH8QHkjRcTCEd88U3ti",
      "url": "https://open.spotify.com/show/1VXcH8QHkjRcTCEd88U3ti",
      "name": "TED Talks Daily",
      "publisher": "TED",
      "images": []
    },
    "images": [
      {
        "url": "https://i.scdn.co/image/trailer",
        "width": 640,
        "height": 640
      }
    ]
  },
  "playable": true,
  "playabilityReason": "PLAYABLE",
  "accessInfo": {
    "isMember": false,
    "title": "Support this show",
    "body": "Some content is available to subscribers.",
    "actionText": "Get access",
    "url": "https://content-access.spotify.com/example",
    "signifier": "Subscriber"
  },
  "gatedRelations": [
    {
      "badges": ["Early access"],
      "summaryForUserWithAccess": "You have early access.",
      "summaryForUserWithoutAccess": "Early access for subscribers.",
      "relatedUri": "spotify:episode:gatedEpisodeId"
    }
  ],
  "episodes": [
    {
      "id": "2XiNimTxVs3P9oC5IAb0eB",
      "uri": "spotify:episode:2XiNimTxVs3P9oC5IAb0eB",
      "url": "https://open.spotify.com/episode/2XiNimTxVs3P9oC5IAb0eB",
      "name": "Why I’m obsessed with health wearables",
      "durationMs": 2925531,
      "releaseDate": "2026-08-07T10:00:00Z",
      "explicit": false,
      "playable": true,
      "show": {
        "id": "1VXcH8QHkjRcTCEd88U3ti",
        "uri": "spotify:show:1VXcH8QHkjRcTCEd88U3ti",
        "url": "https://open.spotify.com/show/1VXcH8QHkjRcTCEd88U3ti",
        "name": "TED Talks Daily",
        "publisher": "TED",
        "images": []
      },
      "images": [
        {
          "url": "https://i.scdn.co/image/episode-cover",
          "width": 640,
          "height": 640
        }
      ]
    }
  ]
}
```

#### Complete `track` output - 42 top-level fields

```json
{
  "recordType": "track",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": "playlist",
  "parentId": "1ew3szJaVPZ9TdEU3Kbl4d",
  "relationType": "playlistTrack",
  "relationId": "playlist-item-uid",
  "position": 1,
  "id": "53iuhJlwXhSER5J2IYYv1W",
  "uri": "spotify:track:53iuhJlwXhSER5J2IYYv1W",
  "url": "https://open.spotify.com/track/53iuhJlwXhSER5J2IYYv1W",
  "name": "The Fate of Ophelia",
  "market": "US",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "durationMs": 226073,
  "explicit": false,
  "contentRating": "NONE",
  "playable": true,
  "playabilityReason": "PLAYABLE",
  "popularity": 96,
  "playCount": 1576303550,
  "trackNumber": 1,
  "discNumber": 1,
  "isLocal": false,
  "isrc": "USUG12500001",
  "ean": null,
  "upc": null,
  "previewUrl": "https://p.scdn.co/mp3-preview/example.mp3",
  "availableMarkets": ["US", "GB"],
  "restrictions": {
    "reason": null,
    "paywallContent": false
  },
  "artists": [
    {
      "id": "06HL4z0CvFAxyc27GXpf02",
      "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
      "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
      "name": "Taylor Swift"
    }
  ],
  "album": {
    "id": "4a6NzYL1YHRUgx9e3YZI6I",
    "uri": "spotify:album:4a6NzYL1YHRUgx9e3YZI6I",
    "url": "https://open.spotify.com/album/4a6NzYL1YHRUgx9e3YZI6I",
    "name": "The Life of a Showgirl",
    "albumType": "ALBUM",
    "releaseDate": "2025-10-03",
    "releaseDatePrecision": "DAY",
    "totalTracks": 12,
    "images": [
      {
        "url": "https://i.scdn.co/image/track-album",
        "width": 640,
        "height": 640
      }
    ],
    "artists": [
      {
        "id": "06HL4z0CvFAxyc27GXpf02",
        "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
        "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
        "name": "Taylor Swift"
      }
    ]
  },
  "images": [
    {
      "url": "https://i.scdn.co/image/track-cover",
      "width": 640,
      "height": 640
    }
  ],
  "credits": [
    {
      "name": "Taylor Swift",
      "role": "Composer",
      "roleGroup": "Composition & Lyrics",
      "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
      "url": "https://artists.spotify.com/songwriter/example"
    }
  ],
  "creditSources": [
    {
      "title": "Source",
      "text": "Credits supplied by the rights holder.",
      "url": null
    }
  ],
  "videoAssociations": 1,
  "audioAssociations": 0,
  "addedAt": "2026-08-01T12:00:00Z",
  "addedBy": {
    "id": "spotify",
    "uri": "spotify:user:spotify",
    "url": "https://open.spotify.com/user/spotify",
    "name": "Spotify",
    "username": "spotify",
    "images": []
  },
  "relationAttributes": {
    "isLocal": false,
    "isEpisode": false
  },
  "matchedFields": []
}
```

For standalone tracks, the six relationship fields and playlist-specific `addedAt`, `addedBy`, and `relationAttributes` values are `null` or empty. Playlist child rows populate them.

#### Complete `album` output - 37 top-level fields

```json
{
  "recordType": "album",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": null,
  "parentId": null,
  "relationType": null,
  "relationId": null,
  "position": null,
  "id": "4a6NzYL1YHRUgx9e3YZI6I",
  "uri": "spotify:album:4a6NzYL1YHRUgx9e3YZI6I",
  "url": "https://open.spotify.com/album/4a6NzYL1YHRUgx9e3YZI6I",
  "name": "The Life of a Showgirl",
  "market": "US",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "albumType": "ALBUM",
  "releaseDate": "2025-10-03",
  "releaseDatePrecision": "DAY",
  "totalTracks": 12,
  "popularity": 95,
  "label": "Taylor Swift",
  "copyrights": [
    {
      "text": "© 2025 Taylor Swift",
      "type": "C"
    }
  ],
  "artists": [
    {
      "id": "06HL4z0CvFAxyc27GXpf02",
      "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
      "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
      "name": "Taylor Swift"
    }
  ],
  "images": [
    {
      "url": "https://i.scdn.co/image/album-cover",
      "width": 640,
      "height": 640
    }
  ],
  "availableMarkets": ["US", "GB"],
  "genres": ["pop"],
  "externalIds": {
    "upc": "602478345678",
    "ean": null
  },
  "playable": true,
  "playabilityReason": "PLAYABLE",
  "isPrerelease": false,
  "prereleaseEndAt": null,
  "saved": false,
  "courtesyLine": null,
  "tracks": [
    {
      "id": "53iuhJlwXhSER5J2IYYv1W",
      "uri": "spotify:track:53iuhJlwXhSER5J2IYYv1W",
      "url": "https://open.spotify.com/track/53iuhJlwXhSER5J2IYYv1W",
      "name": "The Fate of Ophelia",
      "durationMs": 226073,
      "explicit": false,
      "playable": true,
      "playCount": 1576303550,
      "trackNumber": 1,
      "discNumber": 1,
      "artists": [
        {
          "id": "06HL4z0CvFAxyc27GXpf02",
          "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
          "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
          "name": "Taylor Swift"
        }
      ],
      "album": {
        "id": "4a6NzYL1YHRUgx9e3YZI6I",
        "uri": "spotify:album:4a6NzYL1YHRUgx9e3YZI6I",
        "url": "https://open.spotify.com/album/4a6NzYL1YHRUgx9e3YZI6I",
        "name": "The Life of a Showgirl",
        "albumType": "ALBUM",
        "releaseDate": "2025-10-03",
        "releaseDatePrecision": "DAY",
        "totalTracks": 12,
        "images": [
          {
            "url": "https://i.scdn.co/image/album-cover",
            "width": 640,
            "height": 640
          }
        ],
        "artists": [
          {
            "id": "06HL4z0CvFAxyc27GXpf02",
            "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
            "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
            "name": "Taylor Swift"
          }
        ]
      },
      "images": [
        {
          "url": "https://i.scdn.co/image/album-track",
          "width": 640,
          "height": 640
        }
      ]
    }
  ],
  "discs": [
    {
      "number": 1,
      "name": null,
      "trackCount": 12
    }
  ],
  "releases": [
    {
      "id": "4a6NzYL1YHRUgx9e3YZI6I",
      "uri": "spotify:album:4a6NzYL1YHRUgx9e3YZI6I",
      "url": "https://open.spotify.com/album/4a6NzYL1YHRUgx9e3YZI6I",
      "name": "The Life of a Showgirl",
      "albumType": "ALBUM",
      "releaseDate": "2025-10-03",
      "releaseDatePrecision": "DAY",
      "totalTracks": 12,
      "images": [
        {
          "url": "https://i.scdn.co/image/album-release",
          "width": 640,
          "height": 640
        }
      ],
      "artists": [
        {
          "id": "06HL4z0CvFAxyc27GXpf02",
          "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
          "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
          "name": "Taylor Swift"
        }
      ]
    }
  ],
  "moreAlbumsByArtist": [
    {
      "id": "1NAmidJlEaVgA3MpcPFYGq",
      "uri": "spotify:album:1NAmidJlEaVgA3MpcPFYGq",
      "url": "https://open.spotify.com/album/1NAmidJlEaVgA3MpcPFYGq",
      "name": "Lover",
      "albumType": "ALBUM",
      "releaseDate": "2019-08-23",
      "releaseDatePrecision": "DAY",
      "totalTracks": 18,
      "images": [
        {
          "url": "https://i.scdn.co/image/more-album",
          "width": 640,
          "height": 640
        }
      ],
      "artists": [
        {
          "id": "06HL4z0CvFAxyc27GXpf02",
          "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
          "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
          "name": "Taylor Swift"
        }
      ]
    }
  ]
}
```

#### Complete `artist` output - 39 top-level fields

```json
{
  "recordType": "artist",
  "sourceMode": "details",
  "searchTerm": null,
  "parentType": null,
  "parentId": null,
  "relationType": null,
  "relationId": null,
  "position": null,
  "id": "06HL4z0CvFAxyc27GXpf02",
  "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
  "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
  "name": "Taylor Swift",
  "market": "US",
  "locale": "en-US",
  "scrapedAt": "2026-08-08T01:00:00Z",
  "verified": true,
  "followers": 161979413,
  "monthlyListeners": 100887660,
  "worldRank": 6,
  "popularity": 100,
  "genres": ["pop"],
  "biography": "Artist biography.",
  "biographyType": "AUTOBIOGRAPHY",
  "externalLinks": [
    {
      "name": "INSTAGRAM",
      "url": "https://instagram.com/taylorswift"
    }
  ],
  "images": [
    {
      "url": "https://i.scdn.co/image/artist-avatar",
      "width": 640,
      "height": 640
    }
  ],
  "headerImages": [
    {
      "url": "https://i.scdn.co/image/artist-header",
      "width": 2660,
      "height": 1140
    }
  ],
  "galleryImages": [
    {
      "url": "https://i.scdn.co/image/artist-gallery",
      "width": 1200,
      "height": 800
    }
  ],
  "topCities": [
    {
      "city": "London",
      "country": "GB",
      "region": "ENG",
      "listeners": 1604226
    }
  ],
  "topTrackCount": 10,
  "releaseCount": 113,
  "relatedArtistCount": 20,
  "concertCount": 0,
  "merchCount": 0,
  "saved": false,
  "pinnedItem": {
    "type": "ALBUM",
    "uri": "spotify:album:3ZLIShtR6Fjs4nTWFpBUB6",
    "title": "I Knew It, I Knew You",
    "subtitle": "Single",
    "comment": "Featured release",
    "images": [
      {
        "url": "https://i.scdn.co/image/pinned-release",
        "width": 640,
        "height": 640
      }
    ]
  },
  "playlists": [
    {
      "id": "4GtQVhGjAwcHFz82UKy3Ca",
      "uri": "spotify:playlist:4GtQVhGjAwcHFz82UKy3Ca",
      "url": "https://open.spotify.com/playlist/4GtQVhGjAwcHFz82UKy3Ca",
      "name": "Taylor Swift Complete Collection",
      "description": "Official collection",
      "owner": {
        "id": "06HL4z0CvFAxyc27GXpf02",
        "uri": "spotify:user:06HL4z0CvFAxyc27GXpf02",
        "url": "https://open.spotify.com/user/06HL4z0CvFAxyc27GXpf02",
        "name": "Taylor Swift",
        "username": "06HL4z0CvFAxyc27GXpf02",
        "images": []
      },
      "images": [
        {
          "url": "https://i.scdn.co/image/artist-playlist",
          "width": 640,
          "height": 640
        }
      ],
      "totalTracks": 52
    }
  ],
  "topTracks": [
    {
      "id": "53iuhJlwXhSER5J2IYYv1W",
      "uri": "spotify:track:53iuhJlwXhSER5J2IYYv1W",
      "url": "https://open.spotify.com/track/53iuhJlwXhSER5J2IYYv1W",
      "name": "The Fate of Ophelia",
      "durationMs": 226073,
      "explicit": false,
      "playable": true,
      "playCount": 1576303550,
      "trackNumber": 1,
      "discNumber": 1,
      "artists": [
        {
          "id": "06HL4z0CvFAxyc27GXpf02",
          "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
          "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
          "name": "Taylor Swift"
        }
      ],
      "album": {
        "id": "4a6NzYL1YHRUgx9e3YZI6I",
        "uri": "spotify:album:4a6NzYL1YHRUgx9e3YZI6I",
        "url": "https://open.spotify.com/album/4a6NzYL1YHRUgx9e3YZI6I",
        "name": "The Life of a Showgirl",
        "albumType": "ALBUM",
        "releaseDate": "2025-10-03",
        "releaseDatePrecision": "DAY",
        "totalTracks": 12,
        "images": [
          {
            "url": "https://i.scdn.co/image/top-track-album",
            "width": 640,
            "height": 640
          }
        ],
        "artists": [
          {
            "id": "06HL4z0CvFAxyc27GXpf02",
            "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
            "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
            "name": "Taylor Swift"
          }
        ]
      },
      "images": [
        {
          "url": "https://i.scdn.co/image/top-track",
          "width": 640,
          "height": 640
        }
      ]
    }
  ],
  "discography": [
    {
      "id": "4a6NzYL1YHRUgx9e3YZI6I",
      "uri": "spotify:album:4a6NzYL1YHRUgx9e3YZI6I",
      "url": "https://open.spotify.com/album/4a6NzYL1YHRUgx9e3YZI6I",
      "name": "The Life of a Showgirl",
      "albumType": "ALBUM",
      "releaseDate": "2025-10-03",
      "releaseDatePrecision": "DAY",
      "totalTracks": 12,
      "images": [
        {
          "url": "https://i.scdn.co/image/discography-release",
          "width": 640,
          "height": 640
        }
      ],
      "artists": [
        {
          "id": "06HL4z0CvFAxyc27GXpf02",
          "uri": "spotify:artist:06HL4z0CvFAxyc27GXpf02",
          "url": "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
          "name": "Taylor Swift"
        }
      ]
    }
  ],
  "relatedArtists": [
    {
      "id": "1McMsnEElThX1knmY4oliG",
      "uri": "spotify:artist:1McMsnEElThX1knmY4oliG",
      "url": "https://open.spotify.com/artist/1McMsnEElThX1knmY4oliG",
      "name": "Olivia Rodrigo"
    }
  ]
}
```

### What data can you extract?

The following inventory lists every top-level output key. Common relationship fields make nested Spotify collections usable in CSV, SQL, and data warehouses without losing parent context.

| Record | Complete top-level field inventory |
| --- | --- |
| `artist` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `verified`, `followers`, `monthlyListeners`, `worldRank`, `popularity`, `genres`, `biography`, `biographyType`, `externalLinks`, `images`, `headerImages`, `galleryImages`, `topCities`, `topTrackCount`, `releaseCount`, `relatedArtistCount`, `concertCount`, `merchCount`, `saved`, `pinnedItem`, `playlists`, `topTracks`, `discography`, `relatedArtists` |
| `track` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `durationMs`, `explicit`, `contentRating`, `playable`, `playabilityReason`, `popularity`, `playCount`, `trackNumber`, `discNumber`, `isLocal`, `isrc`, `ean`, `upc`, `previewUrl`, `availableMarkets`, `restrictions`, `artists`, `album`, `images`, `credits`, `creditSources`, `videoAssociations`, `audioAssociations`, `addedAt`, `addedBy`, `relationAttributes`, `matchedFields` |
| `album` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `albumType`, `releaseDate`, `releaseDatePrecision`, `totalTracks`, `popularity`, `label`, `copyrights`, `artists`, `images`, `availableMarkets`, `genres`, `externalIds`, `playable`, `playabilityReason`, `isPrerelease`, `prereleaseEndAt`, `saved`, `courtesyLine`, `tracks`, `discs`, `releases`, `moreAlbumsByArtist` |
| `playlist` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `description`, `owner`, `followers`, `following`, `public`, `collaborative`, `snapshotId`, `revisionId`, `totalTracks`, `images`, `members`, `capabilities`, `format`, `tracks` |
| `show` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `publisher`, `description`, `htmlDescription`, `explicit`, `mediaType`, `contentType`, `consumptionOrder`, `languages`, `availableMarkets`, `copyrights`, `images`, `totalEpisodes`, `rating`, `ratingCount`, `topics`, `showTypes`, `trailer`, `playable`, `playabilityReason`, `accessInfo`, `gatedRelations`, `episodes` |
| `episode` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `description`, `htmlDescription`, `durationMs`, `releaseDate`, `releaseDatePrecision`, `explicit`, `contentRating`, `mediaTypes`, `playable`, `playabilityReason`, `previewUrl`, `images`, `show`, `restrictions`, `accessInfo`, `gatedRelations`, `transcripts`, `segments`, `audioUrls` |
| `user` | `recordType`, `sourceMode`, `searchTerm`, `parentType`, `parentId`, `relationType`, `relationId`, `position`, `id`, `uri`, `url`, `name`, `market`, `locale`, `scrapedAt`, `displayName`, `username`, `socialHandle`, `followers`, `followingCount`, `verified`, `reportAbuseDisabled`, `hasSpotifyName`, `hasSpotifyImage`, `profileColor`, `allowFollows`, `showFollows`, `accountId`, `images`, `publicPlaylistCount`, `publicPlaylistsReturned`, `recentlyPlayedArtistCount`, `externalUrls`, `playlists`, `recentlyPlayedArtists` |
| `change` | `recordType`, `sourceMode`, `monitorKey`, `changeType`, `entityType`, `entityId`, `childType`, `childId`, `changedFields`, `before`, `after`, `sourceUrl`, `market`, `locale`, `detectedAt` |
| `error` | `recordType`, `sourceMode`, `input`, `entityType`, `entityId`, `sourceUrl`, `market`, `locale`, `errorType`, `errorMessage`, `httpStatus`, `retryable`, `scrapedAt` |

Nested objects use stable keys:

- Images: `url`, `width`, `height`.
- Artist references: `id`, `uri`, `url`, `name`.
- Album references: `id`, `uri`, `url`, `name`, `albumType`, `releaseDate`, `releaseDatePrecision`, `totalTracks`, `images`, `artists`.
- Track references: `id`, `uri`, `url`, `name`, `durationMs`, `explicit`, `playable`, `playCount`, `trackNumber`, `discNumber`, `artists`, `album`, `images`; playlist track references also contain `position`, `uid`, `addedAt`, `addedBy`, `attributes`.
- Show references: `id`, `uri`, `url`, `name`, `publisher`, `images`.
- Episode references: `id`, `uri`, `url`, `name`, `durationMs`, `releaseDate`, `explicit`, `playable`, `show`, `images`.
- User references: `id`, `uri`, `url`, `name`, `username`, `images`; full user rows also include followers/following, verification and profile flags, `accountId`, public playlists, and recently played artists.
- Credits: `name`, `role`, `roleGroup`, `uri`, `url`; credit sources: `title`, `text`, `url`.
- Monitor sides: `recordKey`, `recordType`, `id`, `parentType`, `parentId`, `relationType`, `relationId`, `values`; each value contains `field` and `value`.

### Input parameters

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `mode` | string | Yes | `search` | `search`, `details`, or `monitor`; one mode per run |
| `searchTerms` | string\[] | Search mode | `["indie pop"]` | Keywords processed independently, maximum 50 terms |
| `entityTypes` | string\[] | Search mode | `artist`, `track`, `playlist` | Any of `artist`, `track`, `album`, `playlist`, `show`, `episode`, `user` |
| `spotifyIds` | string\[] | Details/monitor | Example artist and playlist | Up to 100 public Spotify URLs, URIs, or bare IDs |
| `entityType` | string | No | `auto` | Type for bare references; `auto` recognizes public usernames and probes ambiguous 22-character IDs, while URLs and URIs identify their type |
| `maxResults` | integer | No | `50` | 1–5,000; per term/type in search, or per child collection/input in details and monitor |
| `maxConcurrency` | integer | No | `5` | 1–20 concurrent inputs, enrichments, and Spotify requests |
| `market` | string | No | `US` | Two-letter Spotify market and built-in Residential Proxy country |
| `locale` | string | No | `en-US` | Locale for public localized text |
| `includeDetails` | boolean | No | `false` | Enrich every search result with detail requests |
| `includeTracks` | boolean | No | `true` | Include album and playlist tracks |
| `includeDiscography` | boolean | No | `true` | Include paginated artist releases |
| `includeRelatedArtists` | boolean | No | `false` | Include public related artists |
| `includeCredits` | boolean | No | `true` | Include track contributors and credit sources |
| `includeEpisodes` | boolean | No | `true` | Include paginated podcast/show episodes |
| `includeUserPlaylists` | boolean | No | `true` | Include paginated public playlists for user details |
| `includeUserArtists` | boolean | No | `true` | Include publicly visible recently played artists for users |
| `outputMode` | string | No | `flat` | `nested`, `flat`, or `both` child representation |
| `monitorKey` | string | Monitor mode | `spotify-monitor` | Stable snapshot namespace; 1–80 letters, numbers, dots, dashes, or underscores |
| `emitOnlyChanges` | boolean | No | `true` | In monitor mode, omit current entity rows and return change rows only |

### Use cases

#### Artist and label analytics

Schedule artist details to track monthly listeners, followers, world rank, top cities, top-track plays, and newly published releases. Send `change` rows to a warehouse or notification workflow.

#### Playlist research and monitoring

Find public playlists by keyword, export owners and full track lists, then monitor track additions, removals, position changes, revision IDs, and follower totals.

#### Music catalog enrichment

Enrich internal song or release IDs with names, artist and album relationships, ISRC/UPC values, release dates, labels, playability, market availability, artwork, and structured credits.

#### Podcast discovery and episode tracking

Search shows and episodes, collect ratings, publishers, topics, public access flags, descriptions, and monitor newly published episodes.

#### Audience and trend analysis

Compare artist reach, track plays, playlist placement, release velocity, and regional availability across recurring snapshots.

### Performance and cost

The Actor is ready for Apify pay-per-event billing. Configure prices in the Actor's **Pricing** tab for these stable events:

| Event | Charged for |
| --- | --- |
| `search-result` | One primary entity returned by search |
| `entity-detail` | One root artist, track, album, playlist, show, episode, or user detail row |
| `related-item` | One flat or nested track, release, related artist, public user playlist, recently played artist, or episode |
| `change` | One initialized, added, removed, or modified monitor row |

Explicit error rows are not charged.

The main workload drivers are:

- Number of search terms multiplied by selected entity types and `maxResults`.
- `includeDetails`, which adds detail requests for every search hit.
- Artist discography, playlist tracks, album tracks, and show episodes.
- `both` output, which writes nested parents and separate child rows.
- Residential Proxy transfer, especially the web-player bundle used during token bootstrap.

The Actor processes independent inputs and search enrichments concurrently up to `maxConcurrency`, while a shared request semaphore prevents request bursts above that limit. Pagination inside one logical collection remains ordered. A small test with one input and `maxResults: 10` is recommended before large batches.

### API usage

Replace `[YOUR_USERNAME]` after publishing the Actor:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/[YOUR_USERNAME]~spotify-scraper/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "details",
    "spotifyIds": ["spotify:artist:06HL4z0CvFAxyc27GXpf02"],
    "maxResults": 20,
    "outputMode": "flat"
  }'
```

Use Apify schedules for recurring monitor runs and webhooks to deliver results to Make, Zapier, n8n, Slack, Google Sheets, Airbyte, or a data warehouse.

### Best for / not for

**Best for:** public artist analytics, playlist intelligence, catalog metadata, podcast research, scheduled change detection, and CSV/SQL-friendly exports.

**Not for:** private playlists, private profiles, authenticated library data, playback, DRM-protected media, full audio downloads, lyrics, full transcript downloads, or account automation.

### Limits and good to know

- One mode runs at a time; multiple terms or entity inputs can be processed in one run.
- The Actor limit is 5,000 per child collection or term/type. Spotify can return fewer results or enforce a lower source-side pagination boundary.
- Public user playlist pages are deduplicated by playlist ID. Spotify filters candidates by market, so a page can contain fewer rows than its requested limit; pagination advances by the requested offset until the user limit or an empty page.
- `nested` returns parent rows with child arrays. `flat` returns the parent with empty child arrays plus separate child entity rows. `both` returns populated parents and separate child rows.
- Public URLs and URIs identify their entity type. Bare IDs use `entityType` or automatic endpoint probing.
- `market` controls both source market filtering and the Apify Residential Proxy country. Availability and localized metadata can differ by market.
- All outbound Spotify traffic uses built-in Apify Residential Proxy. The Actor exposes no direct-traffic or user proxy input.
- A sticky proxy session is retained through web-player bootstrap, token generation, and entity requests; sessions rotate after retryable blocking or network failures.
- HTTP 429 responses honor `Retry-After`; expired access tokens are refreshed after HTTP 401.
- Missing public source values remain `null`, `[]`, `{}`, `false`, or `0`. Fixed entity keys are never silently omitted.
- A failed input creates an explicit `error` row while other inputs continue. The Actor fails the run only when every operation ends in a non-terminal failure.
- Monitor snapshots persist by `monitorKey`. Reusing a key compares against the previous successful snapshot; changing the key starts a separate baseline.
- Spotify may change private web-player operations. The Actor obtains current anonymous tokens dynamically, but source changes can still require an Actor update.

### Frequently asked questions

#### What input should I provide?

For search, provide keywords such as `indie pop`. For details or monitoring, provide public URLs, URIs such as `spotify:track:53iuhJlwXhSER5J2IYYv1W`, or bare IDs.

#### Can one run contain different Spotify entity types?

Yes. `spotifyIds` can mix artist, track, album, playlist, show, episode, and user URLs or URIs. Bare IDs need `entityType: auto` or a shared explicit type.

#### How many search rows will I receive?

`maxResults` is per term and selected type. Three types, two terms, and `maxResults: 20` can return up to 120 primary search rows before optional detail children.

#### Why do some search fields contain null or empty arrays?

Basic search cards do not expose every metric. Enable `includeDetails` to request monthly listeners, play counts, credits, full collections, and other available enrichment.

#### How does monitoring work?

Run `monitor` repeatedly with the same `monitorKey`. The first run establishes a baseline; later runs compare fixed normalized rows and emit initialized, added, removed, or modified records. Apify schedules can run it hourly, daily, or weekly.

#### Do I need Spotify credentials, cookies, or a proxy?

No Spotify Developer credentials, OAuth application, login, or cookies are required. The Actor automatically obtains anonymous web-player tokens. Built-in Apify Residential Proxy is mandatory and configured internally.

#### Does the Actor download songs, lyrics, or transcripts?

No. It returns public metadata and public preview URLs when Spotify exposes them. It does not download full audio, reproduce lyrics, or retrieve full transcript bodies.

### Responsible use

This Actor extracts publicly accessible Spotify metadata. Users are responsible for complying with applicable laws, privacy regulations, contractual obligations, and Spotify's terms and policies.

Spotify is a trademark of Spotify AB. This Actor is independent and is not affiliated with, endorsed by, or sponsored by Spotify.

### Support

If a source response changes or a run fails, create an issue in the Actor's **Issues** tab. Include the run ID, mode, market, and a non-sensitive reproducible public Spotify URL. Never post access tokens, client tokens, cookies, or Apify credentials.

### Local development

The Actor targets Python 3.13.

```bash
pip install -r requirements.txt
python -m unittest discover -s tests -v
apify call
```

Local requests still require authenticated access to Apify Residential Proxy. The bundled `free-music-master` directory is retained as the MIT-licensed token-flow reference; the production Actor uses its own asynchronous implementation.

# Actor input Schema

## `mode` (type: `string`):

Search the catalog, fetch rich details, or compare public entities with a previous named monitor snapshot.

## `searchTerms` (type: `array`):

Keywords or phrases processed separately in search mode.

## `entityTypes` (type: `array`):

Spotify entity collections searched for every term. maxResults applies separately to each selected type.

## `spotifyIds` (type: `array`):

Public Spotify entity URLs, spotify:type:id URIs, or bare IDs for details and monitor modes.

## `entityType` (type: `string`):

Type assigned to bare references. Auto recognizes public usernames and probes catalog entity endpoints when needed; URLs and URIs already carry their type.

## `maxResults` (type: `integer`):

Search: maximum rows per term and selected entity type. Details/monitor: maximum child releases, tracks, playlists, or episodes per input.

## `maxConcurrency` (type: `integer`):

Maximum number of independent inputs, enrichments, and Spotify requests processed concurrently. Reduce this if the target starts rate-limiting a large run.

## `market` (type: `string`):

Two-letter country used for Spotify market filtering and mandatory Apify Residential Proxy routing.

## `locale` (type: `string`):

Locale for localized public text, such as en-US, de-DE, or pt-BR.

## `includeDetails` (type: `boolean`):

Run details extraction for every search hit. This returns richer metrics and uses more requests.

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

Collect tracks for album and playlist details and monitoring.

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

Paginate artist albums, singles, EPs, compilations, and appearances up to maxResults.

## `includeRelatedArtists` (type: `boolean`):

Include Spotify's public related-artist collection for artist details.

## `includeCredits` (type: `boolean`):

Collect performers, writers, producers, and engineering credits for track details.

## `includeEpisodes` (type: `boolean`):

Paginate public episodes for show details and monitoring up to maxResults.

## `includeUserPlaylists` (type: `boolean`):

Paginate public playlists for user profile details up to maxResults.

## `includeUserArtists` (type: `boolean`):

Include publicly exposed recently played artists for user profile details, when Spotify makes them visible.

## `outputMode` (type: `string`):

Nested keeps children inside parents, flat emits separate child entity rows, and both does both.

## `monitorKey` (type: `string`):

Stable name for persistent snapshots shared by scheduled monitor runs.

## `emitOnlyChanges` (type: `boolean`):

Return change rows only. Disable to also emit the complete current entity rows on every monitor run.

## Actor input object example

```json
{
  "mode": "search",
  "searchTerms": [
    "indie pop"
  ],
  "entityTypes": [
    "artist",
    "track",
    "playlist"
  ],
  "spotifyIds": [
    "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
    "spotify:playlist:37i9dQZF1DXcBWIGoYBM5M"
  ],
  "entityType": "auto",
  "maxResults": 50,
  "maxConcurrency": 5,
  "market": "US",
  "locale": "en-US",
  "includeDetails": false,
  "includeTracks": true,
  "includeDiscography": true,
  "includeRelatedArtists": false,
  "includeCredits": true,
  "includeEpisodes": true,
  "includeUserPlaylists": true,
  "includeUserArtists": true,
  "outputMode": "flat",
  "monitorKey": "spotify-monitor",
  "emitOnlyChanges": true
}
```

# Actor output Schema

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

Normalized Spotify artist, track, album, playlist, show, episode, user, change, or explicit error rows.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapingmonkey/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapingmonkey/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 '{}' |
apify call scrapingmonkey/spotify-scraper --silent --output-dataset

```

## MCP server setup

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