Skip to main content
Skip to main content

Luke Howsam

Software Engineer

How to use the Spotify API with Next.js

spotify
Published
Share

Create an Application

Initially, we need to generate a Spotify application in order to obtain the neccesary credentials for authenticating with the API

  • Go to your Spotify Developer Dashboard & login

  • Click Create an App

  • Fill out the name and description and click create

  • Click Show Client Secret

  • Save your Client ID and secret somewhere safe, we'll need these later

  • Click Edit settings

  • Add http://localhost:3000 as a redirect URI

You now have a correct Spotify config and the credentials to make requests

Auth

There are a few ways to authenticate with the Spotify API, depending on your app. As we require permission to be granted only once, we will use the authorization code flow: https://developer.spotify.com/documentation/web-api/concepts/authorization#authorization-code-flow

Initially, our app will gather authorization by logging in with the necesary scopes. Below is an example of what the URL will resemble. Remember to swap out the client_id and scopes for your own values:

https://accounts.spotify.com/authorize?client_id=1238e94b895495de7dd
b84a1f7a0e51bf3bc95be8&response_type=code&redirect_uri=http
%3A%2F%2Flocalhost:3000&scope=user-read-currently-playing%20
user-top-read

Following this, you'll be re-directed back to the redirect_uri you specified. Within the URL, you will find a code param. Save this value somewhere safe for later

http://localhost:3000/callback?code=mAwq3...TkDeQ

Next, we will need to obtain the refresh token. You will need to generate a Base64 encoded string that includes the client ID and secret obtained earlier. You can use a tool such as [https://www.base64encode.org/](base64 encode) to do this. The format should adhere to client_id:client_secret.

curl -H "Authorization: Basic <base64 encoded client_id:client_secret>"
-d grant_type=authorization_code -d code=<code> -d redirect_uri=http%3A
%2F%2Flocalhost:3000 https://accounts.spotify.com/api/token

This will return a JSON response containing refresh_token. This token will remain valid indefinitely unless you choose to revoke access, so it's very important to keep this safe and only store it as an environment variable that is only available on the server.

Using the Spotify API

We're now able to use the Spotify API 🥳. In your Next.js app, create the following environment variables

SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
SPOTIFY_REFRESH_TOKEN=

At this stage, we can now request an access token using our client ID, client secret and refresh token


const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`;

const spotifyService = {
  async getAccessToken(): Promise<{ access_token: string }> {
    const response = await fetch(TOKEN_ENDPOINT, {
      method: 'POST',
      headers: {
        Authorization: `Basic ${basic}`,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        refresh_token,
      }),
    });
    return response.json();
    },
}

This access_token will now securely request things such as your top tracks, now playing etc. (this assumes you added the user-top-read scope at the beginning of the post)

Top tracks:


const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`;

  async getTopTracks() {
    const { access_token } = await spotifyService.getAccessToken();

    return fetch(TOP_TRACKS_ENDPOINT, {
      headers: {
        Authorization: `Bearer ${access_token}`,
      },
    });
  },

Creating a route handler

In order to validate that everything is set up correctly with Spotify, let's begin with creating a route handler that communicates with Spotify to get our currently playing song.

// app/api/spotify/now-playing/route.ts

import spotifyService from '@frontend/services/spotifyService';
import { SongItem } from '@frontend/types/spotify';

export const runtime = 'edge';
export const revalidate = 10;

export async function GET() {
  const res = await spotifyService.getNowPlaying();

  if (res.status === 204 || res.status > 400) {
    return new Response(JSON.stringify({ isPlaying: false }), {
      status: 200,
    });
  }

  const song = (await res.json()) as SongItem;

  if (!song.item) {
    return new Response(
      JSON.stringify({
        isPlaying: false,
      }),
      {
        status: 200,
      },
    );
  }
  const isPlaying = song.is_playing;
  const title = song.item.name;
  const artist = song.item.artists
    .map((_artist: { name: string }) => _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 body = JSON.stringify({
    album,
    albumImageUrl,
    artist,
    isPlaying,
    songUrl,
    title,
  });
	
console.log(body)

  return new Response(body, {
    status: 200,
  });
}

This handler will return the currently playing song, formatted to satisfy eslint / remove unneccesary info. If everything is working correctly, you should see some data in the console like the following after running next dev and hitting the endpoint when you're listening to a song on Spotify :)


{
  "album": "Jongen Van De Straat",
  "albumImageUrl": "https://i.scdn.co/image/ab67616d0000b2738d30694491e182ea7e38f517",
  "artist": "Lil Kleine",
  "isPlaying": true,
  "songUrl": "https://open.spotify.com/track/3bhmMwkuZFhgUr9Y6hmjze",
  "title": "Heel Mijn Leven"
}