Get what your currently playing on Spotify
Here we are going to use the Spotify API to get live data on what we are currently playing. You can see this in action on my home page.
Documentation Links
- All Docs → https://developer.spotify.com/documentation/
- Authorisation → https://developer.spotify.com/documentation/general/guides/authorization-guide
- Web API Endpoints → https://developer.spotify.com/documentation/web-api/reference/
Authorising your application
As we are only worried about a single user, we can use the Authorisation Code Flow in a non-dynamic manner.
There are a few steps to complete:
- Create a new app in the developer dashboard (https://developer.spotify.com/) and put the redirect url as a localhost url.
- Get the client id and client secret from the app you created in step 1.
-
Request authorisation for your app:
- Make a GET request to the authorisation URL using the client id
https://accounts.spotify.com/authorize?client_id=your_id&response_type=code&redirect_uri=http://localhost:8000&scope=user-read-currently-playing
- You will be asked to authorise access within the scopes provided.
- This will redirect you back to your localhost URL with a ‘code’ query parameter. This is an authorisation code that can be exchanged for an access token.
- Make a GET request to the authorisation URL using the client id
-
Get a refresh token
-
Make a POST request to
https://accounts.spotify.com/api/token
with the following parameters- grant_type → “authorization_code”
- code → The authorization code from step 3
- redirect_uri → A localhost url again
- Authorization Header → Base 64 encoded string that contains the client ID and client secret key. The field must have the format: Authorization: Basic <base64 encoded client_id:client_secret>
- The response will contain some JSON with your refresh token
{ "access_token": "NgCXRK...MzYjw", "token_type": "Bearer", "scope": "user-read-private user-read-email", "expires_in": 3600, "refresh_token": "NgAagA...Um_SHo" }
- You now have the three environment variables needed to work with the API (client id, client secret and refresh token)
-
Authenticating
Each time we access the API, we must generate an Access Token.
import fetch from 'node-fetch'
import querystring from 'querystring'
const clientID = process.env.CLIENT_ID
const clientSecret = process.env.CLIENT_SECRET
const refreshToken = process.env.REFRESH_TOKEN
const TOKEN_URL = `https://accounts.spotify.com/api/token`
const basicAuth = Buffer.from(`${clientID}:${clientSecret}`).toString('base64')
const getAccessToken = async () => {
const response = await fetch(TOKEN_URL, {
method: 'POST',
headers: {
Authorization: `Basic ${basicAuth}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: querystring.stringify({
grant_type: 'refresh_token',
refresh_token: refreshToken,
}),
})
return response.json()
}
export { getAccessToken }
Fetching the Data
Use the generated Access Token to fetch data.
import { getAccessToken } from '.../your/path/spotify/accessToken';
const NOW_PLAYING_URL = `https://api.spotify.com/v1/me/player/currently-playing`
const getNowPlaying = async () => {
const { access_token } = await getAccessToken()
return fetch(NOW_PLAYING_URL, {
headers: {
Authorization: `Bearer ${access_token}`,
},
})
}
export { getNowPlaying }
Returning the formatted data
Take whatever data you need from the API response and return it to your front end.
import { getNowPlaying } from '.../your/path/spotify';
const handler = async (req, res) => {
const response = await getNowPlaying()
if (response.status === 204 || response.status > 400) {
return res.status(200).json({ isPlaying: false })
}
const song = await response.json()
const isPlaying = song.is_playing
const title = song.item.name
const artist = song.item.artists.map(_artist => _artist.name).join(', ')
const album = song.item.album.name
const albumImageUrl = song.item.album.images[0].url
const songUrl = song.item.external_urls.spotify
const duration = song.item.duration_ms
const progress = song.progress_ms
res.status(200).json({
album,
albumImageUrl,
artist,
isPlaying,
songUrl,
title,
duration,
progress
})
}
export default handler
Example response
{
timestamp: 1629148055966,
context: {
external_urls: {
spotify: 'https://open.spotify.com/playlist/37i9dQZF1E8Ukf867fPCUT'
},
href: 'https://api.spotify.com/v1/playlists/37i9dQZF1E8Ukf867fPCUT',
type: 'playlist',
uri: 'spotify:playlist:37i9dQZF1E8Ukf867fPCUT'
},
progress_ms: 82469,
item: {
album: {
album_type: 'album',
artists: [Array],
available_markets: [Array],
external_urls: [Object],
href: 'https://api.spotify.com/v1/albums/5yaumQgV6xGqCy014aOREt',
id: '5yaumQgV6xGqCy014aOREt',
images: [Array],
name: 'Tubthumper',
release_date: '1997',
release_date_precision: 'year',
total_tracks: 13,
type: 'album',
uri: 'spotify:album:5yaumQgV6xGqCy014aOREt'
},
artists: [ [Object] ],
available_markets: [
'AD', 'AE', 'AG', 'AL', 'AM', 'AO', 'AR', 'AT', 'AU', 'AZ',
'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BN',
'BO', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CH', 'CI', 'CL',
'CM', 'CO', 'CR', 'CV', 'CW', 'CY', 'CZ', 'DE', 'DJ', 'DK',
'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ES', 'FI', 'FJ', 'FM',
'FR', 'GA', 'GB', 'GD', 'GE', 'GH', 'GM', 'GN', 'GQ', 'GR',
'GT', 'GW', 'GY', 'HK', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE',
'IL', 'IN', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH',
'KI', 'KM', 'KN', 'KR', 'KW', 'KZ', 'LA', 'LB', 'LC', 'LI',
'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'MA', 'MC', 'MD', 'ME',
... 75 more items
],
disc_number: 1,
duration_ms: 278778,
explicit: false,
external_ids: { isrc: 'DEA349700542' },
external_urls: {
spotify: 'https://open.spotify.com/track/22HYEJveCvykVDHDiEEmjZ'
},
href: 'https://api.spotify.com/v1/tracks/22HYEJveCvykVDHDiEEmjZ',
id: '22HYEJveCvykVDHDiEEmjZ',
is_local: false,
name: 'Tubthumping',
popularity: 63,
preview_url: 'https://p.scdn.co/mp3-preview/286800bdfa471c2e9e97043988cc203f9dbf8338?cid=a000eccd98744577acf9eebfd7d42297',
track_number: 1,
type: 'track',
uri: 'spotify:track:22HYEJveCvykVDHDiEEmjZ'
},
currently_playing_type: 'track',
actions: { disallows: { resuming: true, skipping_prev: true } },
is_playing: true
}