Playlist Management
Create, modify, and manage Spotify playlists programmatically
Playlists are central to the Spotify experience. This guide covers everything from creating playlists to advanced operations like reordering tracks, managing collaborators, and building playlist generators.
Required Scopes
Section titled “Required Scopes”Different operations require different OAuth scopes:
| Scope | Operations |
|---|---|
playlist-read-private | Read private playlists |
playlist-read-collaborative | Read collaborative playlists |
playlist-modify-public | Create/edit public playlists |
playlist-modify-private | Create/edit private playlists |
ugc-image-upload | Upload custom cover images |
Reading Playlists
Section titled “Reading Playlists”Get Current User’s Playlists
Section titled “Get Current User’s Playlists”import Spotted from "spotted-ts";
const client = new Spotted({ bearerToken: userAccessToken });
// Get playlists with automatic pagination using async iteratorconst playlists = [];for await (const playlist of client.me.playlists.list()) { playlists.push(playlist);}
console.log(`You have ${playlists.length} playlists`);
// Or get a single page of playlistsconst page = await client.me.playlists.list({ limit: 50 });console.log(page.items);Get Playlist Details
Section titled “Get Playlist Details”// Get full playlistconst playlist = await client.playlists.retrieve("37i9dQZF1DXcBWIGoYBM5M");console.log(`${playlist.name}: ${playlist.tracks.total} tracks`);
// Get only specific fields (more efficient)const basicInfo = await client.playlists.retrieve("37i9dQZF1DXcBWIGoYBM5M", { fields: "name,description,owner.display_name,tracks.total",});Get Playlist Tracks
Section titled “Get Playlist Tracks”// Get all tracks using async iteratorconst tracks = [];for await (const item of client.playlists.tracks.list( "37i9dQZF1DXcBWIGoYBM5M", { market: "US", },)) { tracks.push(item.track);}
console.log(`Playlist has ${tracks.length} tracks`);
// Get single page of tracks with specific fieldsconst page = await client.playlists.tracks.list("37i9dQZF1DXcBWIGoYBM5M", { limit: 100, fields: "items(track(id,name,artists,album,duration_ms)),next",});Creating Playlists
Section titled “Creating Playlists”Create a New Playlist
Section titled “Create a New Playlist”// Create a public playlistconst playlist = await client.users.playlists.create("user123", { name: "My Awesome Playlist", description: "A collection of my favorite tracks", public: true,});
console.log(`Created playlist: ${playlist.id}`);
// Create a private collaborative playlistconst collab = await client.users.playlists.create("user123", { name: "Collaborative Mix", public: false, collaborative: true,});Create Playlist with Tracks
Section titled “Create Playlist with Tracks”// Create playlist and add tracksconst playlist = await client.users.playlists.create("user123", { name: "Road Trip Mix", description: "Songs for the journey",});
const trackUris = [ "spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M", // ... more track URIs];
// Add tracks (handles batching automatically for large lists)await client.playlists.tracks.add(playlist.id, { uris: trackUris,});Modifying Playlists
Section titled “Modifying Playlists”Add Tracks
Section titled “Add Tracks”// Add tracks to the endawait client.playlists.tracks.add("playlist123", { uris: [ "spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M", ],});
// Add tracks at a specific position (0 = beginning)await client.playlists.tracks.add("playlist123", { uris: ["spotify:track:newTrackId"], position: 0,});Remove Tracks
Section titled “Remove Tracks”// Remove specific tracksawait client.playlists.tracks.remove("playlist123", { tracks: [{ uri: "spotify:track:4iV5W9uYEdYUVa79Axb7Rh" }],});
// Remove multiple tracksawait client.playlists.tracks.remove("playlist123", { tracks: [{ uri: "spotify:track:track1" }, { uri: "spotify:track:track2" }],});Remove Tracks at Specific Positions
Section titled “Remove Tracks at Specific Positions”// Remove the second occurrence of a track (position 5)await client.playlists.tracks.remove("playlist123", { tracks: [{ uri: "spotify:track:duplicateTrack", positions: [5] }], snapshot_id: "snapshotId123",});Reorder Tracks
Section titled “Reorder Tracks”// Move track from position 0 to position 5await client.playlists.tracks.update("playlist123", { range_start: 0, insert_before: 6,});
// Move tracks 3-5 to the beginningawait client.playlists.tracks.update("playlist123", { range_start: 3, insert_before: 0, range_length: 3,});Replace All Tracks
Section titled “Replace All Tracks”// Replace all tracks (clears playlist first)await client.playlists.tracks.update("playlist123", { uris: ["spotify:track:newTrack1", "spotify:track:newTrack2"],});Update Playlist Details
Section titled “Update Playlist Details”// Update name and descriptionawait client.playlists.update("playlist123", { name: "Updated Playlist Name", description: "New description for the playlist",});
// Make playlist privateawait client.playlists.update("playlist123", { public: false });
// Enable collaborative mode (must be private)await client.playlists.update("playlist123", { public: false, collaborative: true,});Custom Cover Images
Section titled “Custom Cover Images”Upload a custom cover image for your playlist:
import { readFileSync } from "fs";
// Image must be JPEG and base64 encoded, max 256KBconst imageBuffer = readFileSync("cover.jpg");const base64Image = imageBuffer.toString("base64");
await client.playlists.images.upload("playlist123", base64Image);Advanced Playlist Operations
Section titled “Advanced Playlist Operations”Shuffle Playlist
Section titled “Shuffle Playlist”async function shufflePlaylist(playlistId) { // Get all tracks const tracks = []; for await (const item of client.playlists.tracks.list(playlistId)) { tracks.push(item.track); }
const trackUris = tracks.map((t) => `spotify:track:${t.id}`);
// Fisher-Yates shuffle for (let i = trackUris.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [trackUris[i], trackUris[j]] = [trackUris[j], trackUris[i]]; }
// Replace with shuffled order await client.playlists.tracks.update(playlistId, { uris: trackUris.slice(0, 100), });
// Add remaining tracks if more than 100 for (let i = 100; i < trackUris.length; i += 100) { await client.playlists.tracks.add(playlistId, { uris: trackUris.slice(i, i + 100), }); }}Remove Duplicates
Section titled “Remove Duplicates”async function removeDuplicates(playlistId) { const tracks = []; for await (const item of client.playlists.tracks.list(playlistId)) { tracks.push(item.track); }
const seen = new Set(); const duplicatePositions = [];
tracks.forEach((track, index) => { if (seen.has(track.id)) { duplicatePositions.push(index); } else { seen.add(track.id); } });
if (duplicatePositions.length === 0) { console.log("No duplicates found"); return; }
// Get playlist snapshot const playlist = await client.playlists.retrieve(playlistId, { fields: "snapshot_id", }); let snapshotId = playlist.snapshot_id;
// Remove duplicates by position (from end to avoid index shifting) for (let i = duplicatePositions.length - 1; i >= 0; i--) { const position = duplicatePositions[i]; const trackUri = `spotify:track:${tracks[position].id}`;
const result = await client.playlists.tracks.remove(playlistId, { tracks: [{ uri: trackUri, positions: [position] }], snapshot_id: snapshotId, });
snapshotId = result.snapshot_id; }
console.log(`Removed ${duplicatePositions.length} duplicates`);}Sort Playlist by Artist
Section titled “Sort Playlist by Artist”async function sortPlaylistByArtist(playlistId) { const tracks = []; for await (const item of client.playlists.tracks.list(playlistId)) { tracks.push(item.track); }
// Sort by primary artist name const sortedTracks = [...tracks].sort((a, b) => { const artistA = a.artists[0]?.name.toLowerCase() || ""; const artistB = b.artists[0]?.name.toLowerCase() || ""; return artistA.localeCompare(artistB); });
const trackUris = sortedTracks.map((t) => `spotify:track:${t.id}`);
// Replace with sorted tracks await client.playlists.tracks.update(playlistId, { uris: trackUris.slice(0, 100), });
for (let i = 100; i < trackUris.length; i += 100) { await client.playlists.tracks.add(playlistId, { uris: trackUris.slice(i, i + 100), }); }}Building a Playlist Generator
Section titled “Building a Playlist Generator”Create playlists based on specific criteria using the SDK:
import Spotted from "spotted-ts";
const client = new Spotted({ bearerToken: userAccessToken });
// Generate playlist from user's top tracksasync function createTopTracksPlaylist(userId, timeRange = "medium_term") { // Get user's top tracks const topTracks = []; for await (const track of client.me.top.listTracks({ time_range: timeRange, limit: 50, })) { topTracks.push(track); if (topTracks.length >= 50) break; }
// Create playlist const playlist = await client.users.playlists.create(userId, { name: `My Top Tracks (${timeRange.replace("_", " ")})`, description: "Generated from your most played tracks", });
// Add tracks await client.playlists.tracks.add(playlist.id, { uris: topTracks.map((t) => t.uri), });
return playlist;}
// Generate playlist from an artist's discographyasync function createArtistDiscographyPlaylist( userId, artistId, tracksPerAlbum = 5,) { const artist = await client.artists.retrieve(artistId);
const trackUris = []; for await (const album of client.artists.listAlbums(artistId, { include_groups: "album,single", })) { let count = 0; for await (const track of client.albums.listTracks(album.id)) { if (count >= tracksPerAlbum) break; trackUris.push(track.uri); count++; } }
const playlist = await client.users.playlists.create(userId, { name: `${artist.name} - Complete Discography`, description: `All tracks from ${artist.name}'s albums and singles`, });
// Add tracks in batches for (let i = 0; i < trackUris.length; i += 100) { await client.playlists.tracks.add(playlist.id, { uris: trackUris.slice(i, i + 100), }); }
return playlist;}
// Generate workout playlist based on BPMasync function createWorkoutPlaylist(userId, targetBpm = 140, tolerance = 10) { const recs = await client.recommendations.list({ seed_genres: "workout,electronic,hip-hop", target_tempo: targetBpm, min_tempo: targetBpm - tolerance, max_tempo: targetBpm + tolerance, min_energy: 0.7, limit: 50, });
const playlist = await client.users.playlists.create(userId, { name: `Workout Mix (${targetBpm} BPM)`, description: `High-energy tracks around ${targetBpm} BPM`, });
await client.playlists.tracks.add(playlist.id, { uris: recs.tracks.map((t) => t.uri), });
return playlist;}
// Generate mood-based playlistasync function createMoodPlaylist(userId, mood) { const moodSettings = { happy: { target_valence: 0.8, target_energy: 0.7, seed_genres: "pop,dance", }, sad: { target_valence: 0.2, target_energy: 0.3, seed_genres: "acoustic,indie", }, energetic: { target_energy: 0.9, target_danceability: 0.8, seed_genres: "electronic,dance", }, chill: { target_energy: 0.3, target_acousticness: 0.6, seed_genres: "ambient,chill", }, focus: { target_instrumentalness: 0.8, target_energy: 0.5, seed_genres: "classical,ambient", }, party: { target_danceability: 0.9, target_energy: 0.8, seed_genres: "dance,party,edm", }, };
const settings = moodSettings[mood] || moodSettings.happy; const recs = await client.recommendations.list({ ...settings, limit: 50 });
const playlist = await client.users.playlists.create(userId, { name: `${mood.charAt(0).toUpperCase() + mood.slice(1)} Vibes`, description: `A ${mood} playlist generated just for you`, });
await client.playlists.tracks.add(playlist.id, { uris: recs.tracks.map((t) => t.uri), });
return playlist;}
// Usageconst topPlaylist = await createTopTracksPlaylist("user123", "long_term");const discography = await createArtistDiscographyPlaylist( "user123", "06HL4z0CvFAxyc27GXpf02",);const workout = await createWorkoutPlaylist("user123", 150);const chillPlaylist = await createMoodPlaylist("user123", "chill");Collaborative Playlists
Section titled “Collaborative Playlists”Check Followers
Section titled “Check Followers”// Check if users follow the playlistconst follows = await client.playlists.followers.check("playlist123", { ids: "user1,user2",});// Returns [true, false]Follow/Unfollow Playlist
Section titled “Follow/Unfollow Playlist”// Follow a playlist (add to library)await client.playlists.followers.follow("playlist123", { public: true });
// Unfollow a playlist (remove from library)await client.playlists.followers.unfollow("playlist123");Next Steps
Section titled “Next Steps”- User Library - Save tracks and manage your library
- Search & Discovery - Find tracks to add to playlists
- Playback Control - Play your playlists