Spotify API
Integrate the Spotify Web API into TypeScript applications. Covers OAuth 2.0
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 linesSpotify 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
addTracksToPlaylistcall - 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
Related Skills
Discord Bot
Build Discord bots using discord.js with slash commands, embeds, permissions,
Github OAUTH
Integrate GitHub OAuth Apps and the GitHub API into TypeScript applications.
Google OAUTH
Integrate Google OAuth 2.0 and Google APIs into TypeScript applications.
Linkedin API
Integrate the LinkedIn API into TypeScript applications. Covers OAuth 2.0
Notion API
Integrate the Notion API into TypeScript applications. Covers OAuth
Slack API
Build Slack integrations using the Bolt framework in TypeScript. Covers