Note · June 17, 2026

Getting Spotify data in Python without the official API

No app registration, no client ID, no OAuth. How to pull tracks, albums, and playlists — and download a 30-second preview or cover art — straight from Spotify's public web player.

The official Spotify Web API is fine, but it asks for a toll before you’ve read a single field: register an app, keep a client ID and secret, run the OAuth dance, and stay inside its rate limits — all to reach data the web player already shows any browser that opens the link.

For a lot of work — a script, a notebook, a one-off dataset, a small tool — that’s more ceremony than the task deserves. The public web player renders the same metadata as JSON. You can read it directly.

That’s the whole idea behind SpotifyScraper: a typed Python library that reads Spotify’s public pages and hands back clean objects, with no account and no API key. If you’d rather paste a link in the browser first, there’s a live demo.

The thirty-second version

pip install spotifyscraper
from spotify_scraper import SpotifyClient

with SpotifyClient() as client:
    track = client.get_track("https://open.spotify.com/track/0VjIjW4GlUZAMYd2vXMi3b")
    print(track.name, "—", track.artists[0].name)
    print(track.preview_url)   # the public 30-second clip, when one exists
    print(track.to_dict())     # the whole thing, JSON-safe

No SPOTIFY_CLIENT_ID, no token refresh. A link goes in; a typed object comes out. The same call works for albums, artists, playlists, shows, and episodes.

Searching without logging in

You don’t need a link to start. Search reads the anonymous tier the web player uses:

hits = client.search("daft punk", types=("track", "artist"), limit=5)
print(hits.tracks[0].name)
print(hits.artists[0].name)

Downloading a preview or cover art

Most people come for two files: the thirty-second preview and the cover. Both are one call.

with SpotifyClient() as client:
    track = client.get_track(url)
    client.download_preview(track, dest="previews/", embed_cover=True)
    client.download_cover(track, dest="covers/")

Be honest about what these are. The preview is the same ~30-second clip Spotify publishes on the web player — not the full song. Full tracks are DRM-protected, and nothing here changes that; for offline listening, that’s what Premium is for. What you can have, freely, is the public part: the preview, the art, and the metadata around them.

When you want more, and have an account

Lyrics, credits, the Canvas loop, and podcast transcripts live behind a login. Pass your own sp_dc cookie and the library reads them on your behalf — locally, nothing leaving your machine:

lines = client.get_lyrics("4uLU6hMCjMI75M1A2tKUQC")

Async, when you’re pulling a lot

For a batch, the async client lets the network overlap instead of resolving one link at a time:

import asyncio
from spotify_scraper import AsyncSpotifyClient

async def main(urls):
    async with AsyncSpotifyClient() as client:
        tracks = await asyncio.gather(*(client.get_track(u) for u in urls))
        for t in tracks:
            print(t.name)

asyncio.run(main(urls))

How it holds up

Under the hood it’s two tiers — an anonymous access token for search, and Spotify’s GraphQL pathfinder for rich entity reads, with the embed page as a fallback when a shape shifts. It’s built on httpx, sync and async clients over one sans-io core, a single runtime dependency, and typed, frozen models. The point of all that is dull on purpose: what you get back is predictable, and the library survives Spotify’s quiet markup changes without a rewrite — the part of a scraper that actually decides whether it’s still working next month.

It is, deliberately, an unofficial reader of public data. It isn’t affiliated with or endorsed by Spotify, and it’s meant for public metadata, previews, cover art, and research — the things the web player would show you anyway, just typed and scriptable.

If that’s the tool you need: try it in the browser, pip install spotifyscraper, or read the source on GitHub.

boiler room — ali@aliakhtari.com