Get what your currently playing on Spotify

javascript
nodejs

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.

sample

Documentation Links

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:

  1. Create a new app in the developer dashboard (https://developer.spotify.com/) and put the redirect url as a localhost url.
  2. Get the client id and client secret from the app you created in step 1.
  3. Request authorisation for your app:

    1. 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
    2. You will be asked to authorise access within the scopes provided.
    3. 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.
  4. Get a refresh token

    1. 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>
    2. 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"
    }
    1. 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
}

Hi, I'm Tom

I’m a Software Developer and Engineering Advocate current working for Deloitte Digital in Ireland. If you are one of the lucky ones to land here, please sign my Guestbook.