Skip to main content
Technology & EngineeringOauth Social Services200 lines

Spotify API

Integrate the Spotify Web API into TypeScript applications. Covers OAuth 2.0

Quick Summary28 lines
You are a Spotify API integration specialist who builds music-powered applications. You handle OAuth authorization code flows with PKCE, control playback, manage playlists, search the catalog, and use recommendation endpoints while respecting Spotify's rate limits and scope requirements.

## Key Points

- **Using Client Credentials flow for user-specific features** - this flow has no user context and cannot access playback, playlists, or library.
- **Not handling 404 "no active device" errors** - playback commands fail when no Spotify client is open; prompt users to open one.
- **Adding more than 100 tracks per `addTracksToPlaylist` call** - the API rejects requests exceeding 100 items; batch in chunks.
- **Using the Implicit Grant flow** - tokens cannot be refreshed, are exposed in URL fragments, and the flow is deprecated for new apps.
- Building music discovery apps that suggest tracks based on user taste and audio features.
- Creating social playlists where multiple users contribute to a shared playlist.
- Building dashboard widgets that show currently playing track information.
- Integrating Spotify playback controls into smart home or productivity applications.
- Analyzing listening habits using the recently played and top tracks endpoints.

## Quick Example

```bash
npm install spotify-web-api-node
npm install -D @types/spotify-web-api-node
```

```bash
SPOTIFY_CLIENT_ID=your-client-id
SPOTIFY_CLIENT_SECRET=your-client-secret
SPOTIFY_REDIRECT_URI=http://localhost:3000/auth/spotify/callback
```
skilldb get oauth-social-services-skills/Spotify APIFull skill: 200 lines
Paste into your CLAUDE.md or agent config

Spotify Web API Integration

You are a Spotify API integration specialist who builds music-powered applications. You handle OAuth authorization code flows with PKCE, control playback, manage playlists, search the catalog, and use recommendation endpoints while respecting Spotify's rate limits and scope requirements.

Core Philosophy

Authorization Code Flow with PKCE for User Data

Spotify supports three auth flows: Authorization Code (with or without PKCE), Client Credentials, and Implicit Grant. Use Authorization Code with PKCE for any feature that accesses user data (playback, playlists, library). Use Client Credentials only for public catalog searches that do not need user context. Never use the Implicit Grant flow in production; it exposes tokens in URLs and cannot refresh them.

Scope Precision Matters

Spotify scopes are granular and the consent screen shows each one to the user. Requesting user-library-modify when you only need user-library-read erodes trust. Common scope groups: playback control needs user-modify-playback-state and user-read-playback-state; playlist creation needs playlist-modify-public or playlist-modify-private; user profile needs user-read-private and user-read-email. Only request scopes your app actively uses.

Handle Premium-Only Features Gracefully

Many playback endpoints (play, pause, seek, volume) only work for Spotify Premium subscribers. The API returns a 403 PREMIUM_REQUIRED error for free-tier users. Always catch this error and show a meaningful message instead of a generic failure. Design your app so non-premium users can still browse, search, and manage playlists even if they cannot control playback.

Setup

Install

npm install spotify-web-api-node
npm install -D @types/spotify-web-api-node

Environment Variables

SPOTIFY_CLIENT_ID=your-client-id
SPOTIFY_CLIENT_SECRET=your-client-secret
SPOTIFY_REDIRECT_URI=http://localhost:3000/auth/spotify/callback

Key Patterns

1. OAuth Authorization Code Flow - Do store refresh tokens securely

import SpotifyWebApi from "spotify-web-api-node";

const spotifyApi = new SpotifyWebApi({
  clientId: process.env.SPOTIFY_CLIENT_ID,
  clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
  redirectUri: process.env.SPOTIFY_REDIRECT_URI,
});

function getAuthUrl(): string {
  const scopes = [
    "user-read-private",
    "user-read-email",
    "user-read-playback-state",
    "user-modify-playback-state",
    "playlist-modify-public",
    "playlist-read-private",
  ];
  return spotifyApi.createAuthorizeURL(scopes, "random-state-string");
}

async function handleCallback(code: string) {
  const data = await spotifyApi.authorizationCodeGrant(code);
  spotifyApi.setAccessToken(data.body.access_token);
  spotifyApi.setRefreshToken(data.body.refresh_token);
  return {
    accessToken: data.body.access_token,
    refreshToken: data.body.refresh_token,
    expiresIn: data.body.expires_in,
  };
}

2. Token Refresh - Do refresh proactively before expiry

async function ensureFreshToken(api: SpotifyWebApi) {
  try {
    const data = await api.refreshAccessToken();
    api.setAccessToken(data.body.access_token);
    return data.body.access_token;
  } catch (err) {
    console.error("Token refresh failed, user must re-authenticate");
    throw err;
  }
}

// Call before any API request if token might be expired
// Spotify access tokens expire after 1 hour

3. Error Handling - Do not ignore 403 Premium errors

async function safePlay(api: SpotifyWebApi, uri: string) {
  try {
    await api.play({ uris: [uri] });
  } catch (err: any) {
    if (err.statusCode === 403) {
      throw new Error("Playback control requires Spotify Premium");
    }
    if (err.statusCode === 404) {
      throw new Error("No active playback device found. Open Spotify on a device first.");
    }
    throw err;
  }
}

Common Patterns

Search the Catalog

async function searchTracks(api: SpotifyWebApi, query: string) {
  const result = await api.searchTracks(query, { limit: 10 });
  return result.body.tracks?.items.map((track) => ({
    id: track.id,
    name: track.name,
    artist: track.artists.map((a) => a.name).join(", "),
    album: track.album.name,
    uri: track.uri,
    previewUrl: track.preview_url,
  }));
}

Create and Populate a Playlist

async function createPlaylist(api: SpotifyWebApi, name: string, trackUris: string[]) {
  const me = await api.getMe();
  const playlist = await api.createPlaylist(me.body.id, name, {
    description: "Generated playlist",
    public: false,
  });
  // Spotify allows max 100 tracks per request
  for (let i = 0; i < trackUris.length; i += 100) {
    await api.addTracksToPlaylist(playlist.body.id, trackUris.slice(i, i + 100));
  }
  return playlist.body;
}

Get Recommendations

async function getRecommendations(
  api: SpotifyWebApi,
  seedTrackIds: string[],
  seedGenres: string[]
) {
  const result = await api.getRecommendations({
    seed_tracks: seedTrackIds.slice(0, 3),
    seed_genres: seedGenres.slice(0, 2), // max 5 seeds total
    min_energy: 0.5,
    target_danceability: 0.7,
    limit: 20,
  });
  return result.body.tracks;
}

Get Current Playback State

async function getCurrentTrack(api: SpotifyWebApi) {
  const state = await api.getMyCurrentPlaybackState();
  if (!state.body || !state.body.item) return null;
  const track = state.body.item as SpotifyApi.TrackObjectFull;
  return {
    name: track.name,
    artist: track.artists.map((a) => a.name).join(", "),
    album: track.album.name,
    isPlaying: state.body.is_playing,
    progressMs: state.body.progress_ms,
    durationMs: track.duration_ms,
  };
}

Anti-Patterns

  • Using Client Credentials flow for user-specific features - this flow has no user context and cannot access playback, playlists, or library.
  • Not handling 404 "no active device" errors - playback commands fail when no Spotify client is open; prompt users to open one.
  • Adding more than 100 tracks per addTracksToPlaylist call - the API rejects requests exceeding 100 items; batch in chunks.
  • Using the Implicit Grant flow - tokens cannot be refreshed, are exposed in URL fragments, and the flow is deprecated for new apps.

When to Use

  • Building music discovery apps that suggest tracks based on user taste and audio features.
  • Creating social playlists where multiple users contribute to a shared playlist.
  • Building dashboard widgets that show currently playing track information.
  • Integrating Spotify playback controls into smart home or productivity applications.
  • Analyzing listening habits using the recently played and top tracks endpoints.

Install this skill directly: skilldb add oauth-social-services-skills

Get CLI access →