Bimal Thapa Magar
⋅
1 year ago
⋅
7 min read
Want to show your top ten Spotify tracks and now playing songs on your portfolio website built with the latest Next.js App router (v14.0.1)? This is the gudie for you that will walk you through the process, starting from scratch, to showcase both your currently playing song and the top 10 tracks you've been listening to on Spotify
You need to follow these step by step guide in order to integrate Spotify's API.
Firstly, you need to authenticate yourself in order to get access for fetching the Spotify's API.And, for that you need to create an spotify application. Here are the steps:
http://localhost:3000
as your redirect URI.client_id
and just below that you will see View client secret button.client_id
and client_secret
.Both will be needed later.Congratulations!, now you have all credentials in order to authenticate the Spotify's APIs.
Now, it's time to authenticate the Spotify API using the previously saved credentials. Spotify offers various Authorization methods, and for now, we'll be utilizing the Authorization Code Flow.
Initially, our application needs to be authorized with specific
scopes. Scopes
serve the purpose of granting confidence to share only the selected information and nothing beyond that.
For instance, in my application, I only intend to retrieve the top ten tracks and the currently playing song
from Spotify's Developer API. To achieve this, I must select the scopes user-top-read
and user-read-currently-playing
from the scopes list respectively.
Here's an example of the URL for authorization with these scopes.
https://accounts.spotify.com/authorize?client_id=<client_id_you_saved_before>&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000&scope=user-read-currently-playing%20user-top-read
Now, copy the provided URL and paste it into your browser's address bar. Ensure that your localhost:3000
is running.
is actively running. After pressing enter, you'll be redirected to http://localhost:3000?code=
, where you will receive
a code as a query parameter. Here's an example of the URL you can expect at this stage.
http://localhost:3000/?code=AQB3x..............................
Now, save this code.You will need it later for retrieving your refresh_token
.
Next, you will need to generate the refresh_token
in order to revoke the access_token
--which expires frequently.For that
open up your terminal and then type the following code.
curl -d client_id=<your_client_id> -d client_secret=<your_client_secret> -d grant_type=authorization_code -d code=<code_that_you_saved_from_redirected_uri> -d redirect_uri=http://localhost:3000 https://accounts.spotify.com/api/token
You now will get the JSON response in the following format.
{
"access_token":"your_access_token_here",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"your_refresh_token_here",
"scope":"user-read-currently-playing"
}
After that save the refresh_token
from the response and save it for later.You will need to use this in Next.js application. This refresh_token
is valid indefinitely until
and unless the user it represents revokes access.
Firstly, you have to set up the environment variables
in .env
file outside the app
directory in your next js application.Add the environment variables as below.Replace these values
with your own values you saved before like before.
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
SPOTIFY_REFRESH_TOKEN=
Secondly, let's create a lib/spotify.js
, to look more organized folder structure, where we will be writing the API fetching
logic. Your code should look like this.
import queryString from 'query-string';
const client_id = process.env.SPOTIFY_CLIENT_ID;
const client_secret = process.env.SPOTIFY_CLIENT_SECRET;
const refresh_token = process.env.SPOTIFY_REFRESH_TOKEN;
const basic = Buffer.from(`${client_id}:${client_secret}`).toString('base64');
const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`;
const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`;
const TOP_TRACKS_ENDPOINT = `https://api.spotify.com/v1/me/top/tracks`;
//After the access_token expires, getting new access_token with refresh_token we obtained before
const getAccessToken = async () => {
try {
const response = await fetch(TOKEN_ENDPOINT,{
method:'POST',
headers:{
Authorization:`Basic ${basic}`,
'Content-Type':'application/x-www-form-urlencoded'
},
body:queryString.stringify({
grant_type:'refresh_token',
refresh_token
})
});;
const responseData = await response.json();
return responseData;
} catch(err){
throw new Error(JSON.stringify(err))
}
};
//Get currently playing song
export const getNowPlaying = async () => {
try {
const {access_token} = await getAccessToken();
return fetch(NOW_PLAYING_ENDPOINT,{
headers:{
Authorization:`Bearer ${access_token}`
}
});
} catch(err){
throw new Error(JSON.stringify(err))
}
};
//Get top tracks played on your Spotify account
export const getTopTracks = async () => {
try {
const {access_token} = await getAccessToken();
return fetch(TOP_TRACKS_ENDPOINT,{
headers:{
Authorization:`Bearer ${access_token}`
}
});
} catch(err){
throw new Error(JSON.stringify(err))
}
};
Cheers 🥂!, Everything is setup. Now at last we need to setup two api routes in order to send the requests
and get response from the spotify's API. For that you have to create two files app/api/now-playing/route.js
and app/api/top-tracks/route.js
in your application.The equivalent code for those two endpoints looks like this.
import { NextResponse } from 'next/server'
import {getNowPlaying} from "../../../lib/spotify";
export const dynamic = 'force-dynamic';
//--------------OR---------------------//
export const revalidate = 0;
export async function GET(request) {
const response = await getNowPlaying();
if(response?.status === 204 || response?.status > 400) {
return NextResponse.json({isPlaying:false},{status:200});
}
try {
const song = await response.json();
console.log('song',song?.item?.name);
const isPlaying = song?.is_playing;
const name = 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?.album.external_urls.spotify;
return NextResponse.json({
isPlaying,
album,
albumImageUrl,
name,
songUrl,
artist
},{
status:200
});
} catch(err) {
return NextResponse.json({
isPlaying:false
},{
status:200
});
}
}
import { NextResponse } from 'next/server'
import {getTopTracks} from "../../../lib/spotify";
export const dynamic = 'force-dynamic';
//--------------OR----------------------//
export const revalidate = 0;
export async function GET(request) {
const response = await getTopTracks();
if(response.status === 204 || response.status > 400) {
return NextResponse.json({tracks:[]},{status:200});
}
try {
const {items} = await response.json();
const tracks = items.slice(0,10).map(track => {
return {
artist:track.artists.map(artist => artist.name).join(", "),
songUrl:track.external_urls.spotify,
title:track.name,
imageUrl:track.album.images.map(image => image.url)[1]
};
});
return NextResponse.json({tracks},{
status:200
});
} catch(err){
return NextResponse.json({tracks},{status:200});
}
}
Note: In the provided code, you'll notice two lines as shown below 👇. You can choose either of them; both are optional, and you can select the one you prefer. This flexibility exists because, by default, the Next.js App router caches routes. This means that if the same endpoint is accessed from the client side, the router utilizes the cached response. If you don't use these options, your "now-playing" endpoint may not update, resulting in the same cached response being displayed and causing a failure to show the currently playing music in the UI.Additinally, feel free to modify the JSON response from those endpoints as per your need or demand.
export const dynamic = 'force-dynamic';
//-----------OR----------------------//
export const revalidate = 0;
Everything is complete! Now it's time to retrieve data from the two endpoints you've established. This is the way to showcase your top ten tracks and currently playing songs on your Next.js website, allowing users to see what you're listening to.
POV: You have the option to utilize swr, react query or official fetch api or client-side data fetching in React.js. For simplicity, I'll be using swr. Here's a code snippet demonstrating how to implement SWR for this particular use case.
import useSWR from 'swr';
const YourClientComponent = () => {
//Fetch data in a periodical interval of 1 seconds
const {data,error} = useSWR('/api/now-playing',fetcher,{refreshInterval:1000});
return (
<div>
{
error && <p> Oops! Error dude 👀 </p>
}
{
data?.isPlaying ? (<h1>{data?.name}</h1>):<p>Not Playing</p>
}
</div>
)
};
export default YourClientComponent;
Consequently, you can integrate Spotify's API like as such in Next.js APP Router.Follow me on 👉 GitHub.
Keep coding, Keep learning and Keep listening music 🎸.😜😜
Not Playing