May 20, 2024•3 min read
I love when developer portfolios have a bit of personality. It's not just about the code; it's about the person behind the keyboard. One small detail I added to my site is a "Now Playing" card that shows what I'm listening to on Spotify in real-time. It's a fun little glimpse into my day (and my questionable music taste).
Here's how I built it using the Spotify API and Next.js.
The Setup
First things first, you need to tell Spotify you're building an app. Go to the Spotify Developer Dashboard and create an app. You'll need the Client ID and Client Secret.
The tricky part is authentication. Since we want this to work server-side without a user logging in every time, we need a Refresh Token. This allows our app to request a new Access Token whenever it needs one, effectively keeping us logged in forever.
Add these to your .env.local:
SPOTIFY_CLIENT_ID=...
SPOTIFY_CLIENT_SECRET=...
SPOTIFY_REFRESH_TOKEN=...The Backend
I use a utility file to handle the authentication. We encode the Client ID and Secret in base64 and send them to Spotify's token endpoint to get an access token.
const basic = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
export async function getAccessToken() {
const response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
Authorization: `Basic ${basic}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
}),
});
return response.json();
}Now, we can create an API route to fetch the currently playing song. This is what our frontend will hit.
import { getAccessToken } from 'lib/spotify';
export async function GET() {
const { access_token } = await getAccessToken();
const response = await fetch('https://api.spotify.com/v1/me/player/currently-playing', {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
if (response.status === 204 || response.status > 400) {
return Response.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;
return Response.json({
album,
albumImageUrl,
artist,
isPlaying,
songUrl,
title,
});
}Notice how we filter the response? The Spotify API returns a ton of data. We only pick what we need to keep the payload light.
The Frontend
Finally, the React component. It simply fetches data from our API route and displays it.
export function SpotifyCard({ data }) {
const isPlaying = data?.isPlaying;
if (!isPlaying) {
return (
<div className="flex items-center gap-4">
<p>Not listening to anything right now.</p>
</div>
);
}
return (
<div className="flex items-center gap-4">
<img
src={data.albumImageUrl}
alt={data.album}
className="w-16 h-16 rounded-md"
/>
<div className="flex flex-col">
<a
href={data.songUrl}
target="_blank"
rel="noopener noreferrer"
className="font-medium hover:underline"
>
{data.title}
</a>
<p className="text-gray-500 text-sm">{data.artist}</p>
</div>
</div>
);
}And there you have it! A live connection to your Spotify, right on your blog. It's a simple feature, but it adds that dynamic, personal touch that makes a site feel alive.