Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Spotify Web API Node

TestsCoverage Status

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

It includes helper functions to do the following:

Music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity
  • Get current user’s recently played tracks

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Get a user's available devices
  • Get information about the user's current playback
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests, and promise as its Promises/A+ implementation.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

varSpotifyWebApi=require('spotify-web-api-node');// credentials are optionalvarspotifyApi=newSpotifyWebApi({clientId : 'fcecfc72172e4cd267473117a17cbd4d',clientSecret : 'a6338157c9bb5ac9c71924cb2940e1a7',redirectUri : 'http://www.example.com/callback'});

If you've got an access token and want to use it for all calls, simply use the api object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20},function(err,data){if(err){console.error('Something went wrong!');}else{console.log(data.body);}});

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is currently required if you're using callback methods.

// Passing a callback - get Elvis' albums in range [20...29]spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10,offset: 20}).then(function(data){console.log('Album information',data.body);},function(err){console.error(err);});

Response body, statuscode, and headers

To enable caching, this wrapper now exposes the response headers and not just the response body. Since version 2.0.0, the response object has the format

{
"body" : {
},
"headers" : {
},
"statusCode" :
}

In previous versions, the response object was the same as the response body.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later

{
"body":
{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
},
"headers": {
"date": "Fri, 27 Feb 2015 09:25:48 GMT",
"content-type": "application/json; charset=utf-8",
"cache-control": "public, max-age=7200",
},
"statusCode": 200
}

The response object for the same request in earlier versions than to 2.0.0.

{
"name": "Golpe Maestro",
"popularity": 42,
"preview_url": "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
"track_number": 1,
"type": "track",
"uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

Please note that since version 1.3.2 all methods accept an optional callback method as their last parameter. These examples however only use promises.

varSpotifyWebApi=require('spotify-web-api-node');varspotifyApi=newSpotifyWebApi();// Get multiple albumsspotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm','3KyVcddATClQKIdtaap4bV']).then(function(data){console.log('Albums information',data.body);},function(err){console.error(err);});// Get an artistspotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3').then(function(data){console.log('Artist information',data.body);},function(err){console.error(err);});// Get multiple artistsspotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3','6J6yx1t3nwIDyPXk5xa7O8']).then(function(data){console.log('Artists information',data.body);},function(err){console.error(err);});// Get albums by a certain artistspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(function(data){console.log('Artist albums',data.body);},function(err){console.error(err);});// Search tracks whose name, album or artist contains 'Love'spotifyApi.searchTracks('Love').then(function(data){console.log('Search by "Love"',data.body);},function(err){console.error(err);});// Search artists whose name contains 'Love'spotifyApi.searchArtists('Love').then(function(data){console.log('Search artists by "Love"',data.body);},function(err){console.error(err);});// Search tracks whose artist's name contains 'Love'spotifyApi.searchTracks('artist:Love').then(function(data){console.log('Search tracks by "Love" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar').then(function(data){console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name',data.body);},function(err){console.log('Something went wrong!',err);});// Search playlists whose name or description contains 'workout'spotifyApi.searchPlaylists('workout').then(function(data){console.log('Found playlists are',data.body);},function(err){console.log('Something went wrong!',err);});// Get tracks in an albumspotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ',{limit : 5,offset : 1}).then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get an artist's top tracksspotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy','GB').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});// Get artists related to an artistspotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for a Track */spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Analysis for a Track */spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK').then(function(data){console.log(data.body);},function(err){done(err);});/* Get Audio Features for several tracks */spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh','3Qm86XLflmIXVm1wcwkgDK']).then(function(data){console.log(data.body);},function(err){done(err);});/* * User methods */// Get a userspotifyApi.getUser('petteralexis').then(function(data){console.log('Some information about this user',data.body);},function(err){console.log('Something went wrong!',err);});// Get the authenticated userspotifyApi.getMe().then(function(data){console.log('Some information about the authenticated user',data.body);},function(err){console.log('Something went wrong!',err);});/* * Playlist methods */// Get a playlistspotifyApi.getPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Some information about this playlist',data.body);},function(err){console.log('Something went wrong!',err);});// Get a user's playlistsspotifyApi.getUserPlaylists('thelinmichael').then(function(data){console.log('Retrieved playlists',data.body);},function(err){console.log('Something went wrong!',err);});// Create a private playlistspotifyApi.createPlaylist('thelinmichael','My Cool Playlist',{'public' : false}).then(function(data){console.log('Created playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"]).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Add tracks to a specific position in a playlistspotifyApi.addTracksToPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',["spotify:track:4iV5W9uYEdYUVa79Axb7Rh","spotify:track:1301WleyT98MSxVHPZCA6M"],{position : 5}).then(function(data){console.log('Added tracks to playlist!');},function(err){console.log('Something went wrong!',err);});// Remove tracks from a playlist at a specific positionspotifyApi.removeTracksFromPlaylistByPosition('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',[0,2,130],"0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9").then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Remove all occurrence of a trackvartracks=[{uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}];varoptions={snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9"};spotifyApi.removeTracksFromPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',tracks,options).then(function(data){console.log('Tracks removed from playlist!');},function(err){console.log('Something went wrong!',err);});// Reorder the first two tracks in a playlist to the place before the track at the 10th positionvaroptions={"range_length" : 2};spotifyApi.reorderTracksInPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',0,10,options).then(function(data){console.log('Tracks reordered in playlist!');},function(err){console.log('Something went wrong!',err);});// Change playlist detailsspotifyApi.changePlaylistDetails('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{name: 'This is a new name for my Cool Playlist, and will become private','public' : false}).then(function(data){console.log('Playlist is now private!');},function(err){console.log('Something went wrong!',err);});// Follow a playlist (privately)spotifyApi.followPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',{'public' : false}).then(function(data){console.log('Playlist successfully followed privately!');},function(err){console.log('Something went wrong!',err);});// Unfollow a playlistspotifyApi.unfollowPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK').then(function(data){console.log('Playlist successfully unfollowed!');},function(err){console.log('Something went wrong!',err);});// Check if Users are following a PlaylistspotifyApi.areFollowingPlaylist('thelinmichael','5ieJqeLJjjI8iJWaxeBLuK',['thelinmichael','ella']).then(function(data){data.body.forEach(function(isFollowing){console.log("User is following: "+isFollowing);});},function(err){console.log('Something went wrong!',err);});/* * Following Users and Artists methods *//* Get followed artists */spotifyApi.getFollowedArtists({limit : 1}).then(function(data){// 'This user is following 1051 artists!'console.log('This user is following ',data.body.artists.total,' artists!');},function(err){console.log('Something went wrong!',err);});/* Follow a user */// TBD./* Follow an artist */// TBD./* Unfollow a user */// TBD/* Unfollow an artist */// TBD/* Check if a user is following a user */// TBD/* Check if a user is following an artist */// TBD/* * Your Music library methods *//* Tracks */// Get tracks in the signed in user's Your Music libraryspotifyApi.getMySavedTracks({limit : 2,offset: 1}).then(function(data){console.log('Done!');},function(err){console.log('Something went wrong!',err);});// Check if tracks are in the signed in user's Your Music libraryspotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"]).then(function(data){// An array is returned, where the first element corresponds to the first track ID in the queryvartrackIsInYourMusic=data.body[0];if(trackIsInYourMusic){console.log('Track was found in the user\'s Your Music library');}else{console.log('Track was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove tracks from the signed in user's Your Music libraryspotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add tracks to the signed in user's Your Music libraryspotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"]).then(function(data){console.log('Added track!');},function(err){console.log('Something went wrong!',err);});});/* Albums */// Get albums in the signed in user's Your Music libraryspotifyApi.getMySavedAlbums({limit : 1,offset: 0}).then(function(data){// Output itemsconsole.log(data.body.items);},function(err){console.log('Something went wrong!',err);});// Check if albums are in the signed in user's Your Music libraryspotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){// An array is returned, where the first element corresponds to the first album ID in the queryvaralbumIsInYourMusic=data.body[0];if(albumIsInYourMusic){console.log('Album was found in the user\'s Your Music library');}else{console.log('Album was not found.');}},function(err){console.log('Something went wrong!',err);});// Remove albums from the signed in user's Your Music libraryspotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Removed!');},function(err){console.log('Something went wrong!',err);});});// Add albums to the signed in user's Your Music libraryspotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"]).then(function(data){console.log('Added album!');},function(err){console.log('Something went wrong!',err);});});/* * Browse methods */// Retrieve new releasesspotifyApi.getNewReleases({limit : 5,offset: 0,country: 'SE'}).then(function(data){console.log(data.body);done();},function(err){console.log("Something went wrong!",err);});});// Retrieve featured playlistsspotifyApi.getFeaturedPlaylists({limit : 3,offset: 1,country: 'SE',locale: 'sv_SE',timestamp:'2014-10-23T09:00:00'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a List of CategoriesspotifyApi.getCategories({limit : 5,offset: 0,country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get a Category (in Sweden)spotifyApi.getCategory('party',{country: 'SE',locale: 'sv_SE'}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});// Get Playlists for a Category (Party in Brazil)spotifyApi.getPlaylistsForCategory('party',{country: 'BR',limit : 2,offset : 0}).then(function(data){console.log(data.body);},function(err){console.log("Something went wrong!",err);});/* Get Recommendations Based on Seeds */// TBD/** * Personalization Endpoints *//* Get a User’s Top Artists and Tracks */// TBDGetaUser’sTopArtistsandTracks

Nesting calls

// track detail information for album tracksspotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm').then(function(data){returndata.body.tracks.map(function(t){returnt.id;});}).then(function(trackIds){returnspotifyApi.getTracks(trackIds);}).then(function(data){console.log(data.body);}).catch(function(error){console.error(error);});// album detail for the first 10 Elvis' albumsspotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE',{limit: 10}).then(function(data){returndata.body.albums.map(function(a){returna.id;});}).then(function(albums){returnspotifyApi.getAlbums(albums);}).then(function(data){console.log(data.body);});

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports two authorization flows - The Authorization Code flow (signed by a user), and the Client Credentials flow (application authentication - the user isn't involved). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use those methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to our Accounts service. Generate the URL by using the wrapper's authorization URL method.

varscopes=['user-read-private','user-read-email'],redirectUri='https://example.com/callback',clientId='5fe01282e44241328a84e7c5cc169165',state='some-state-of-my-choice';// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.varspotifyApi=newSpotifyWebApi({redirectUri : redirectUri,clientId : clientId});// Create the authorization URLvarauthorizeURL=spotifyApi.createAuthorizeURL(scopes,state);// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choiceconsole.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

varcredentials={clientId : 'someClientId',clientSecret : 'someClientSecret',redirectUri : 'http://www.michaelthelin.se/test-callback'};varspotifyApi=newSpotifyWebApi(credentials);// The code that's returned as a query parameter to the redirect URIvarcode='MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';// Retrieve an access token and a refresh tokenspotifyApi.authorizationCodeGrant(code).then(function(data){console.log('The token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);console.log('The refresh token is '+data.body['refresh_token']);// Set the access token on the API object to use it in later callsspotifyApi.setAccessToken(data.body['access_token']);spotifyApi.setRefreshToken(data.body['refresh_token']);},function(err){console.log('Something went wrong!',err);});

Since the access token was set on the api object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed unless it has expired.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.spotifyApi.refreshAccessToken().then(function(data){console.log('The access token has been refreshed!');// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Could not refresh access token',err);});

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

varclientId='someClientId',clientSecret='someClientSecret';// Create the api object with the credentialsvarspotifyApi=newSpotifyWebApi({clientId : clientId,clientSecret : clientSecret});// Retrieve an access token.spotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token expires in '+data.body['expires_in']);console.log('The access token is '+data.body['access_token']);// Save the access token so that it's used in future callsspotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong when retrieving an access token',err);});

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by onevarspotifyApi=newSpotifyWebApi();spotifyApi.setAccessToken('myAccessToken');spotifyApi.setRefreshToken('myRefreshToken');spotifyApi.setRedirectURI('http://www.example.com/test-callback');spotifyApi.setClientId('myOwnClientId');spotifyApi.setClientSecret('someSuperSecretString');// Set all credentials at the same timespotifyApi.setCredentials({'accessToken' : 'myAccessToken','refreshToken' : 'myRefreshToken','redirectUri' : 'http://www.example.com/test-callback','clientId ' : 'myClientId','clientSecret' : 'myClientSecret'});// Get the credentials one by oneconsole.log('The access token is '+spotifyApi.getAccessToken());console.log('The refresh token is '+spotifyApi.getRefreshToken());console.log('The redirectURI is '+spotifyApi.getRedirectURI());console.log('The client ID is '+spotifyApi.getClientId());console.log('The client secret is '+spotifyApi.getClientSecret());// Get all credentialsconsole.log('The credentials are '+spotifyApi.getCredentials());// Reset the credentialsspotifyApi.resetAccessToken();spotifyApi.resetRefreshToken();spotifyApi.resetRedirectURI();spotifyApi.resetClientId();spotifyApi.resetClientSecret();spotifyApi.resetCode();// Reset all credentials at the same timespotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructorvarspotifyApi=newSpotifyWebApi({clientId : 'myClientId',clientSecret : 'myClientSecret'});// Get an access token and 'save' it using a setterspotifyApi.clientCredentialsGrant().then(function(data){console.log('The access token is '+data.body['access_token']);spotifyApi.setAccessToken(data.body['access_token']);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Do search using the access tokenspotifyApi.searchTracks('artist:Love').then(function(data){console.log(data.body);},function(err){console.log('Something went wrong!',err);});
// Set the credentials when making the requestvarspotifyApi=newSpotifyWebApi({accessToken : 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'});// Get tracks in a playlistapi.getPlaylistTracks('thelinmichael','3ktAYNcRHpazJ9qecm3ptn',{'offset' : 1,'limit' : 5,'fields' : 'items'}).then(function(data){console.log('The playlist contains these tracks',data.body);},function(err){console.log('Something went wrong!',err);});

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing mocha and get a test coverage report running mocha -r blanket -R html-cov > coverage.html.

About

A Node.js wrapper for Spotify's Web API.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages