DEV Community

Alex Spinov
Alex Spinov

Posted on • Edited on

Spotify API: Build a Music Discovery Tool in 50 Lines of Python

Spotify's API is one of the most generous free APIs available. You get access to 100 million tracks, audio features, recommendations, and playlist data — all for free.

Here's how to build a music discovery tool in 50 lines.

Setup (2 Minutes)

  1. Go to developer.spotify.com
  2. Create an app (free)
  3. Copy your Client ID and Client Secret
pip install httpx
Enter fullscreen mode Exit fullscreen mode

Authentication

Spotify uses Client Credentials flow for public data:

import httpx
import base64

CLIENT_ID = 'your_client_id'
CLIENT_SECRET = 'your_client_secret'

def get_token():
    auth = base64.b64encode(f'{CLIENT_ID}:{CLIENT_SECRET}'.encode()).decode()
    r = httpx.post('https://accounts.spotify.com/api/token',
        headers={'Authorization': f'Basic {auth}'},
        data={'grant_type': 'client_credentials'}
    )
    return r.json()['access_token']

token = get_token()
headers = {'Authorization': f'Bearer {token}'}
Enter fullscreen mode Exit fullscreen mode

Search for Artists

def search_artist(name):
    r = httpx.get('https://api.spotify.com/v1/search',
        headers=headers,
        params={'q': name, 'type': 'artist', 'limit': 1}
    )
    artist = r.json()['artists']['items'][0]
    return {
        'name': artist['name'],
        'id': artist['id'],
        'followers': artist['followers']['total'],
        'genres': artist['genres'],
        'popularity': artist['popularity']
    }

print(search_artist('Radiohead'))
# {'name': 'Radiohead', 'followers': 11M, 'genres': ['art rock', ...], 'popularity': 79}
Enter fullscreen mode Exit fullscreen mode

Get Top Tracks

def top_tracks(artist_id, market='US'):
    r = httpx.get(f'https://api.spotify.com/v1/artists/{artist_id}/top-tracks',
        headers=headers,
        params={'market': market}
    )
    return [{
        'name': t['name'],
        'album': t['album']['name'],
        'popularity': t['popularity'],
        'preview_url': t['preview_url']
    } for t in r.json()['tracks'][:5]]
Enter fullscreen mode Exit fullscreen mode

Get Audio Features (The Cool Part)

Spotify analyzes every track and provides:

  • danceability — how suitable for dancing (0-1)
  • energy — intensity and activity (0-1)
  • valence — musical positivity (0-1)
  • tempo — BPM
  • acousticness — acoustic vs electronic (0-1)
def audio_features(track_id):
    r = httpx.get(f'https://api.spotify.com/v1/audio-features/{track_id}',
        headers=headers
    )
    f = r.json()
    return {
        'danceability': f['danceability'],
        'energy': f['energy'],
        'valence': f['valence'],
        'tempo': f['tempo'],
        'acousticness': f['acousticness']
    }
Enter fullscreen mode Exit fullscreen mode

Discover Similar Artists

def discover(artist_name):
    """Find similar artists with different vibes."""
    artist = search_artist(artist_name)
    r = httpx.get(f'https://api.spotify.com/v1/artists/{artist["id"]}/related-artists',
        headers=headers
    )
    related = r.json()['artists'][:10]
    return [{
        'name': a['name'],
        'genres': a['genres'][:3],
        'popularity': a['popularity'],
        'followers': f"{a['followers']['total']:,}"
    } for a in related]

# Find artists similar to Radiohead
for artist in discover('Radiohead'):
    print(f"{artist['name']} ({artist['popularity']}/100) — {', '.join(artist['genres'])}")
Enter fullscreen mode Exit fullscreen mode

Get Recommendations

def get_recommendations(seed_artists=None, seed_genres=None, **kwargs):
    params = {'limit': 10}
    if seed_artists:
        params['seed_artists'] = ','.join(seed_artists)
    if seed_genres:
        params['seed_genres'] = ','.join(seed_genres)
    params.update(kwargs)  # target_energy=0.8, min_tempo=120, etc.

    r = httpx.get('https://api.spotify.com/v1/recommendations',
        headers=headers, params=params
    )
    return [{'name': t['name'], 'artist': t['artists'][0]['name']} 
            for t in r.json()['tracks']]

# High energy dance tracks
recs = get_recommendations(
    seed_genres=['electronic', 'dance'],
    target_energy=0.9,
    target_danceability=0.8,
    min_tempo=120
)
Enter fullscreen mode Exit fullscreen mode

Rate Limits

  • Free tier: ~180 requests/minute
  • No API key cost
  • Rate limit headers in response

What You Can Build

  • Mood-based playlist generator
  • Artist similarity explorer
  • Music taste analyzer
  • Genre evolution tracker
  • DJ set builder (match BPM/key)

More API Tutorials


What would you build with the Spotify API? Mood playlists? Music analytics? Something else? 👇

API tutorials at dev.to/0012303


More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs


Need web scraping or data extraction? I've built 77+ production scrapers. Email spinov001@gmail.com — quote in 2 hours. Or try my ready-made Apify actors — no code needed.

Top comments (1)

Collapse
 
jakemoreno_dev profile image
Jake Moreno

really cool tutorial, the audio features endpoint is the hidden gem here imo. being able to pull stuff like acousticness and valence opens up some interesting possibilities for building mood-based playlists.

one thing I've been messing with lately is using the related artists endpoint to map out genre connections — like starting from a folk artist and seeing how many hops it takes to get to metal lol. the recommendation seeds are powerful for that kind of exploration too.

quick question — have you run into any issues with the audio features endpoint returning null for certain tracks? I noticed some newer releases sometimes don't have that data populated right away. curious if you found a workaround or if it's just a timing thing on Spotify's end.