Spotify Scraper: Playlists, Albums, Artists & Tracks Metadata
Pricing
from $0.50 / 1,000 track or releases
Spotify Scraper: Playlists, Albums, Artists & Tracks Metadata
Scrape Spotify metadata by link: every track of a playlist or an album, an artist's top tracks and releases, single tracks. Track id, name, artists, album, release date, duration, explicit, track number, play count, preview and cover URLs; playlist owner and followers. No login.
Pricing
from $0.50 / 1,000 track or releases
Rating
0.0
(0)
Developer
Hyperbach
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Spotify metadata by link, logged out: every track of a playlist or an album, an artist's top tracks and releases, and single tracks — the track id and URL, name, artists, album, release date, duration, the explicit flag, disc and track number, the play count, the 30-second preview URL and the cover URL, with the playlist's name, owner and followers on a playlist's tracks — several links in one run, a max per link. One free list row per link carries a completeness verdict: COMPLETE (every item of Spotify's count), CAPPED (your limit) or PARTIAL. No login, no API key, no browser, proxies handled for you. Never the audio.
Why this Spotify scraper
- Playlists, albums, artists and tracks in one run. Paste open.spotify.com links (with
/intl-xx/,/embed/or?si=, as you copy them) orspotify:URIs, one a line. A playlist gives its tracks, an album its tracks, an artist its top tracks and its releases, a track its own row. Each link gets its own cap (maxItemsPerUrl), and the run's cap sits on top (maxItems). - The play count on every track. Spotify's all-time stream count comes with each track of a playlist, an album or an artist, beside the album, the release date, the duration, the explicit flag and the disc and track number.
- Whole playlists, checked. A playlist is read page after page in Spotify's own order until every item of Spotify's count is read: the free
listrow says COMPLETE with the count (a 421-track playlist in one page, measured 2026-10-23). A track the playlist lists twice is delivered once; podcast episodes are counted and skipped. - Playlist context on every track. A playlist's tracks carry the playlist's name, owner and follower count and the date each track was added; an artist's list row carries its followers, monthly listeners and world rank.
- Honest runs. An id Spotify does not know is a free
not_foundrow, checked twice; a link that is not Spotify a freeinvalidrow. Every link gets a row.
Who it's for
- Music marketers and labels — the tracks of the playlists that matter to an artist, with each track's play count and the playlist's followers, read again every week.
- Playlist curators and researchers — whole playlists with the date each track was added, the owner and the follower count, to follow what a playlist adds and drops.
- Music data apps — an artist's releases and top tracks, or an album's tracks, with release dates, durations, track numbers, covers and preview URLs.
Quick start
The four kinds of link, 10 rows each
{"startUrls": ["https://open.spotify.com/track/0VjIjW4GlUZAMYd2vXMi3b","https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj","https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02","https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"],"maxItemsPerUrl": 10}
Every track of a playlist
{"startUrls": ["https://open.spotify.com/playlist/37i9dQZF1DX4UtSsGT1Sbe"],"maxItemsPerUrl": 0}
An artist's whole discography (releases only)
{"startUrls": ["https://open.spotify.com/artist/1Xyo4u8uXC1ZmMpatF05PJ"],"artistRows": "releases","maxItemsPerUrl": 0}
Output
One row per track or release (and one free list row per link):
| field | meaning |
|---|---|
row_type | track (one track, charged), album (one release of an artist, charged) or list (the link's row with the walk's verdict; free). |
input_index | The 1-based position of the link this row answers in startUrls. |
input_value | The link as you gave it. |
input_type | What the link is: playlist, album, artist or track (empty for a value that is not a Spotify link). |
input_id | The link's Spotify id (22 letters and digits). |
input_url | The link on open.spotify.com, as a URL you can open. |
status | A list row: ok, not_found, invalid, duplicate, failed or not_read (see the FAQ). A track or album row: ok. |
status_detail | Why a list row is not ok, in a sentence. |
scraped_at | When the row was read (UTC). |
position | The row's place in the link's own list: the playlist's order, the album's order, the top-tracks rank (1-10), the releases' order (newest first); 1 for a track link. |
track_id | The track's Spotify id. |
track_url | The track on open.spotify.com. |
track_uri | The track's Spotify URI (spotify:track:<id>). |
name | The track's name; on an album row the release's name; on a list row the playlist's, album's, artist's or track's name. |
artists | The track's artists, in Spotify's order; on an album row the artist of the link. |
artist_ids | The Spotify ids of artists, in the same order. |
album_id | The Spotify id of the track's album (or of the release, on an album row). |
album_url | The album on open.spotify.com. |
album_name | The album's name. |
album_type | album, single, ep or compilation, when the answer names it (an album's tracks, an artist's top tracks and releases, a track link). |
label | The record label, on an album's tracks and on an album link's list row. |
release_date | The album's release date: YYYY-MM-DD, or YYYY-MM / YYYY when Spotify knows only the month or the year. |
duration_ms | The track's length in milliseconds. |
explicit | True when Spotify marks the track explicit. |
disc_number | The disc the track is on (1 for most albums; empty on a track link). |
track_number | The track's number on its disc. |
play_count | Spotify's play count of the track (all-time streams; Spotify shows 0 until a track passes 1,000). |
preview_url | The 30-second preview's URL from the link's embed player: every track of an album, an artist's top tracks, a track link, and the first 100 tracks of a playlist (later tracks have none). Never the audio file itself. |
cover_url | The album cover (the largest size, 640 px); on a list row the playlist's, album's or artist's image. |
playable | False when Spotify marks the track or release not playable for the reader's country. |
added_at | A playlist's track: when it was added to the playlist (UTC). |
total_tracks | An album row: the release's number of tracks; an album link's list row: the album's. |
playlist_id | A playlist's track: the playlist's id. |
playlist_name | A playlist's track: the playlist's name. |
playlist_owner | A playlist's track: the owner's display name (Spotify for Spotify's own playlists). |
playlist_owner_id | A playlist's track: the owner's Spotify user id. |
playlist_followers | A playlist's track: the playlist's followers. |
owner | A playlist's list row: the owner's display name. |
owner_id | A playlist's list row: the owner's Spotify user id. |
followers | A list row: the playlist's or the artist's followers. |
monthly_listeners | An artist's list row: Spotify's monthly listeners. |
world_rank | An artist's list row: Spotify's world rank, when the artist has one. |
items_count | A list row: Spotify's own count of the link's list (a playlist's items, an album's tracks, an artist's top tracks and releases). |
items_delivered | A list row: the track and release rows delivered for the link. |
pages_read | A list row: the pages of the list read. |
repeats_skipped | A list row: tracks skipped because the same list already listed them (a playlist can hold a track twice). |
other_items_skipped | A list row: items that are not tracks (podcast episodes, local files, items Spotify no longer serves): counted, not delivered. |
verdict | A list row: COMPLETE (every item of Spotify's count, or Spotify's own end of the list), CAPPED (your limit) or PARTIAL (a refusal, an empty page below the count, or the time limit stopped it). |
verdict_detail | A list row: the verdict in a sentence, with the counts. |
Example record:
{"row_type": "track","input_index": 2,"input_value": "https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj","input_type": "album","input_id": "4yP0hdKOZPNshxUOjY0cZj","input_url": "https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj","status": "ok","status_detail": null,"scraped_at": "2026-10-23T06:39:05Z","position": 1,"track_id": "6b5P51m8xx2XA6U7sdNZ5E","track_url": "https://open.spotify.com/track/6b5P51m8xx2XA6U7sdNZ5E","track_uri": "spotify:track:6b5P51m8xx2XA6U7sdNZ5E","name": "Alone Again","artists": ["The Weeknd"],"artist_ids": ["1Xyo4u8uXC1ZmMpatF05PJ"],"album_id": "4yP0hdKOZPNshxUOjY0cZj","album_url": "https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj","album_name": "After Hours","album_type": "album","label": "Republic Records","release_date": "2020-03-20","duration_ms": 250053,"explicit": true,"disc_number": 1,"track_number": 1,"play_count": 233244354,"preview_url": "https://p.scdn.co/mp3-preview/77e54c6064335e259d0f571768af5f96c22304d4","cover_url": "https://i.scdn.co/image/ab67616d0000b2738863bc11d2aa12b54f5aeb36","playable": true,"added_at": null,"total_tracks": null,"playlist_id": null,"playlist_name": null,"playlist_owner": null,"playlist_owner_id": null,"playlist_followers": null,"owner": null,"owner_id": null,"followers": null,"monthly_listeners": null,"world_rank": null,"items_count": null,"items_delivered": null,"pages_read": null,"repeats_skipped": null,"other_items_skipped": null,"verdict": null,"verdict_detail": null}
Pricing
Pay for the tracks and releases a run delivers, plus one run start; no platform usage is billed to you. The row price falls with your Apify plan.
| event | unit | Free | Starter | Scale | Business |
|---|---|---|---|---|---|
Track or release (result) | per 1,000 | $1.00 | $0.85 | $0.70 | $0.50 |
Run start (start) | per run | $0.001 | $0.001 | $0.001 | $0.001 |
A track or release row is $1.00 per 1,000 on the Free plan ($0.001 a row). Each run that delivers a charged row also pays the run start, $0.001 once; a run that delivers no charged row pays nothing at all. So one playlist of 100 tracks costs $0.101 on the Free plan, and several links in one run share one start. The free list row of every link, a value that is not a Spotify link (invalid), an id Spotify does not know (not_found), a repeated link (duplicate), a link left at the cap or the time limit (not_read) and a refusal the run could not pass (failed) are never charged. A run that stops early (a timeout, an abort) is charged for the rows it delivered. maxItems counts the charged rows; before the first request the log names the price of each row at your plan and the most the run can cost. Enterprise plans have their own rates: the Actor's Pricing tab shows the price for your plan.
Usage patterns
- Links —
startUrlstakes open.spotify.com links of playlists (/playlist/<id>), albums (/album/<id>), artists (/artist/<id>) and tracks (/track/<id>), with or without/intl-xx/,/embed/and?si=, andspotify:<kind>:<id>URIs. Podcasts, users and short spotify.link links are not read (a freeinvalidrow says so). - What a row is —
row_type=track: one track, in the link's own order (position).row_type=album: one release of an artist (albums, singles, EPs and compilations, newest first).row_type=list: the free row of one link — its name, owner or followers,items_count(Spotify's own count),items_delivered,pages_read,repeats_skipped,other_items_skipped, theverdictwith itsverdict_detail, and thestatuswith its reason. - How far a link goes —
maxItemsPerUrl(default 100; 0 = every track or release the link serves) stops each playlist, album or artist after that many rows. A playlist or an album is read to Spotify's count; an artist gives its top tracks (Spotify lists up to 10) and then its releases, asartistRowschooses.maxItemscaps the charged rows of the whole run.
Input configuration
| field | type | default | what it does |
|---|---|---|---|
startUrls | array | Spotify links to read, one a line: a playlist (https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M: its tracks), an album (its tracks), an artist (its top tracks and its releases) or a track (its own row). Links with /intl-xx/, /embed/ or ?si= and spotify:track:<id> URIs work too. A link that is not a Spotify playlist, album, artist or track (a podcast, a user, a short spotify.link) gets a free invalid row; a link given twice a free duplicate row. | |
maxItemsPerUrl | integer | 100 | Stop each playlist, album or artist after this many rows (tracks, or an artist's top tracks and releases together). 0 = every track or release the link serves. A track link is one row. |
artistRows | both / top_tracks / releases | "both" | What an artist link gives: its top tracks (up to 10, Spotify's own list) and then its releases (albums, singles, EPs and compilations, newest first), the top tracks only, or the releases only. |
maxItems | integer | 0 | Stop the whole run after this many track and release rows (the charged rows). 0 = no run cap; each link still stops at its own limit above. |
Errors
A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:
- the status message starts with
INPUT REJECTED; - the dataset holds one row,
{"error": true, "code": "…", "message": "…"}, and no results; - the key-value store record
ERRORholds the same object.
From code, check error on the first row before reading results.
A value that is not a Spotify playlist, album, artist or track link (a podcast, a user page, a short spotify.link link) is not an error: it gets one free list row with status invalid that says why, and the run goes on with the others. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.
FAQ
Which status is which?
A list row's status is ok (rows served), not_found (Spotify has no playlist, album, artist or track with that id; checked on two connections), invalid (an empty value, or a value that is not a Spotify playlist, album, artist or track link), duplicate (the same link again in the input: read once), failed (Spotify refused every try; free) or not_read (left at maxItems, the charge limit or the run's time limit). A track or album row's status is ok.
Does it give the popularity score or the ISRC?
No. Spotify serves the popularity score and the ISRC through its developer Web API, which refuses a logged-out reader (measured 2026-10-23); the web player serves the play count (all-time streams) instead, and that is on every track row.
Does every track have a preview URL?
Every track of an album, an artist's top tracks and a track link have one when Spotify offers a preview. A playlist's embed player lists its first 100 tracks, so later tracks of a long playlist have no preview URL. The actor never downloads the audio.
Does it need a Spotify account or API key?
No. Everything is read from Spotify's public pages and its web player, logged out.
Integration
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('hyperbach/spotify-scraper').call({"startUrls": ["https://open.spotify.com/track/0VjIjW4GlUZAMYd2vXMi3b", "https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj", "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"], "maxItemsPerUrl": 10});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python
from apify_client import ApifyClientclient = ApifyClient('YOUR_TOKEN')run = client.actor('hyperbach/spotify-scraper').call(run_input={'startUrls': ['https://open.spotify.com/track/0VjIjW4GlUZAMYd2vXMi3b', 'https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj', 'https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02', 'https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M'], 'maxItemsPerUrl': 10})items = client.dataset(run['defaultDatasetId']).list_items().items
CLI
$apify call hyperbach/spotify-scraper --input '{"startUrls": ["https://open.spotify.com/track/0VjIjW4GlUZAMYd2vXMi3b", "https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj", "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"], "maxItemsPerUrl": 10}'
REST
curl -X POST "https://api.apify.com/v2/acts/hyperbach~spotify-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H 'Content-Type: application/json' -d '{"startUrls": ["https://open.spotify.com/track/0VjIjW4GlUZAMYd2vXMi3b", "https://open.spotify.com/album/4yP0hdKOZPNshxUOjY0cZj", "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M"], "maxItemsPerUrl": 10}'
Support
This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.