I wanted to display what song I'm currently listening to on my site. Since I'm always listening to Spotify, this is the API I'm had to integrate. This post will be a quick rundown of the steps needed to integrate Spotify.
Here's a visual representation of the Spotify integration:
And here are the steps needed to integrate:
Create an Application
First, create a Spotify application for authentication credentials.
- Go to the Spotify Developer Dashboard and log in.
- Click Create an App, fill in the form and click create.
- Click Show Client Secret to get your Client ID and Secret.
- Add
http://localhost:3000
as the redirect URI in the settings.
Now you have a Spotify application with the necessary credentials.
Authentication
We'll use the Authorization Code Flow for one-time permission.
- Request authorization with the following URL (replace
client_id
and scopes):
https://accounts.spotify.com/authorize?client_id=1abe4bac63b1436e8e809
8fd25088ced&response_type=code&redirect_uri=http://localhost:3000&
scope=user-read-currently-playing%20user-top-read
-
After authorizing, you'll be redirected to your redirect_uri with a code query parameter. Save this value.
-
Retrieve the refresh token using a Base 64 encoded string of your client ID and secret (To encode the strings, I used this tool):
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
Save the refresh_token
from the JSON response in an environment variable.
Using Spotify's API
Add these values to your .env file in the app:
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
SPOTIFY_REDIRECT_URI=
Request an access code with your credentials:
import { URLSearchParams } from 'url';
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 TOKEN_ENDPOINT = 'https://accounts.spotify.com/api/token';
export const getSpotifyAccessToken = async (): Promise<string> => {
const basic = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
const params = new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: REFRESH_TOKEN,
});
try {
const response = await fetch(TOKEN_ENDPOINT, {
method: 'POST',
headers: {
Authorization: `Basic ${basic}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.access_token;
} catch (error) {
console.error('Error fetching access token:', error);
throw error;
}
};
Use the access_token
to fetch the track you currently listen to:
export type SpotifyNowPlaying = {
albumImageUrl: string;
artist: string;
isPlaying: boolean;
songUrl: string;
title: string;
timePlayed: number;
timeTotal: number;
artistUrl: string;
};
export const getSpotifyNowPlaying = async (): Promise<SpotifyNowPlaying> => {
const { access_token } = await getSpotifyAccessToken();
const response = await fetch(NOW_PLAYING_ENDPOINT, {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
const song = await response.json();
const albumImageUrl = song.item.album.images[0].url;
const artist = song.item.artists.map((artist) => artist.name).join(", ");
const isPlaying = song.is_playing;
const songUrl = song.item.external_urls.spotify;
const title = song.item.name;
const timePlayed = song.progress_ms;
const timeTotal = song.item.duration_ms;
const artistUrl = song.item.album.artists[0].external_urls.spotify;
return {
albumImageUrl,
artist,
isPlaying,
songUrl,
title,
timePlayed,
timeTotal,
artistUrl,
};
};
That's it! You now have the data. Now to the actual component to display that song.
The component I ended up making:
export const NowPlaying = (spotifyNowPlaying: SpotifyNowPlaying) => {
if (!spotifyNowPlaying) return null;
return (
<div className="grid text-center lg:mb-0 lg:grid-cols-2 lg:text-left ">
{!spotifyNowPlaying.isPlaying && (
<div className="flex items-center gap-2">
<SpotifyIcon className="text-[#1DB954]/75" />
<span className="text-gray-500 dark:text-gray-400">
Currently offline
</span>
</div>
)}
{spotifyNowPlaying.isPlaying && (
<a
href={spotifyNowPlaying.songUrl}
target="_blank"
rel="noreferrer"
className=""
>
<div className="flex items-center gap-2">
<SpotifyIcon className="text-[#1DB954]/75" height={18} width={18} />
<span className="text-gray-500 dark:text-gray-400">
Now playing
</span>
</div>
<div className="flex items-center gap-2 rounded-lg border border-transparent px-5 mr-2 mt-2 py-4 transition-colors border-gray-300 hover:bg-gray-100 dark:border-neutral-700 hover:dark:bg-neutral-800/30">
<Image
className="rounded"
width={52}
height={52}
src={spotifyNowPlaying.albumImageUrl}
alt={`${spotifyNowPlaying.title} album art`}
/>
<div>
<div className="flex items-center gap-2">
<PlayingAnimation />
<div>{spotifyNowPlaying.title}</div>
</div>
<p className="text-gray-500 dark:text-gray-400">
{spotifyNowPlaying.artist}
</p>
</div>
</div>
</a>
)}
</div>
);
};
If you paid close attention there is also a moving Spotify animation next to the song. I took a lot of inspiration from this article. I copied the design and the animation, but adapted it to use tailwindcss.
That's really it! Enjoy :-)