DEV Community

Cover image for How to Add a Spotify Recently Played Widget to Your Astro Portfolio
Timy
Timy

Posted on

How to Add a Spotify Recently Played Widget to Your Astro Portfolio

🎧 Why Add a Spotify Widget?

A portfolio site doesn’t have to be just another static page — small personal details can make it stand out.

A Spotify recently played widget does exactly that:

  • It makes your portfolio feel alive — showing what you’re listening to right now.
  • It adds personality. Employers, clients, or fellow developers get a glimpse of your taste in music.
  • It’s dynamic. Unlike static text, the widget updates automatically whenever you play music on Spotify.

Instead of only saying “I build cool things with Astro,” your site also says, “Here’s what I was vibing to last night while coding.”


🛠️ What You’ll Build

By the end of this tutorial, you’ll have a widget that:

✅ Connects to Spotify’s Web API

✅ Fetches your recently played track in real-time

✅ Displays album art, song, and artist info

✅ Runs with a secure Astro server endpoint


⚡ TL;DR

  • Get your Spotify API credentials.
  • Use Bruno to generate a refresh token.
  • Create an Astro API endpoint to fetch data from Spotify.
  • Display the widget in your portfolio.

📋 Prerequisites

Make sure you have:

  • Node.js and npm installed
  • Spotify Developer Account – needed to register your app and get credentials.
  • A Bruno API Client (to handle OAuth flow easily)
  • Basic understanding of Astro projects

💡 If you’ve never used Bruno before, think of it as a modern alternative to Postman. Lightweight, open-source, and perfect for testing APIs.


🚀 Step 1 — Create a New Astro Project

If you don’t have one already:

npm create astro@latest my-spotify-portfolio
cd my-spotify-portfolio
npm install
Enter fullscreen mode Exit fullscreen mode

Your project structure will look like this:

/
├── src/
│   ├── components/
│   ├── layouts/
│   ├── pages/
│   └── content/
├── public/
└── astro.config.mjs
Enter fullscreen mode Exit fullscreen mode

🔐 Step 2 — Authenticate with Spotify Using Bruno

Spotify requires OAuth 2.0 Authorization Code Flow.

For a portfolio widget, we don’t want users to log in — so we’ll use a refresh token.

Here’s how:

  1. Open Bruno and create a new request.
  2. Under Auth → OAuth 2.0 → Authorization Code, fill in:
  • Callback URL: http://localhost:3000/callback
  • Authorization URL: https://accounts.spotify.com/authorize
  • Access Token URL: https://accounts.spotify.com/api/token
  • Client ID / Secret: from your Spotify app
  • Scope: user-read-recently-played
  1. Click Get New Access Token. Bruno will give you both an access_token (short-lived) and a refresh_token (long-lived).

✅ Save the refresh_token — we’ll use it in the next step.

Bruno Image


🧠 Step 3 — Create an Astro Server Endpoint

Astro’s server endpoints act as backend routes inside your project — no external serverless function required.

First, create a .env file:

SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
SPOTIFY_REFRESH_TOKEN=your_refresh_token
Enter fullscreen mode Exit fullscreen mode

Now create your API route:

// src/pages/api/spotify-recently-played.ts
export const prerender = false;
import type { APIRoute } from "astro";

export const GET: APIRoute = async () => {
  const client_id = import.meta.env.SPOTIFY_CLIENT_ID!;
  const client_secret = import.meta.env.SPOTIFY_CLIENT_SECRET!;
  const refresh_token = import.meta.env.SPOTIFY_REFRESH_TOKEN!;

  try {
    // 1. Get a new access token
    const tokenResponse = await fetch("https://accounts.spotify.com/api/token", {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Authorization: "Basic " + Buffer.from(client_id + ":" + client_secret).toString("base64"),
      },
      body: new URLSearchParams({
        grant_type: "refresh_token",
        refresh_token,
      }),
    });

    const tokenData = await tokenResponse.json();
    if (!tokenResponse.ok) throw new Error(tokenData.error_description);
    const access_token = tokenData.access_token;

    // 2. Fetch the recently played track
    const recentRes = await fetch(
      "https://api.spotify.com/v1/me/player/recently-played?limit=1",
      { headers: { Authorization: `Bearer ${access_token}` } }
    );

    const recentData = await recentRes.json();
    const latest = recentData.items?.[0]?.track;
    if (!latest) {
      return new Response(JSON.stringify({ error: "No recent track found" }), { status: 404 });
    }

    // 3. Send a clean JSON response
    return new Response(
      JSON.stringify({
        albumCover: latest.album.images[0]?.url || null,
        song: latest.name,
        artist: latest.artists.map((a: any) => a.name).join(", "),
        spotifyUrl: latest.external_urls.spotify,
      }),
      { status: 200, headers: { "Content-Type": "application/json" } }
    );
  } catch (err: any) {
    return new Response(JSON.stringify({ error: err.message }), { status: 500 });
  }
};
Enter fullscreen mode Exit fullscreen mode

Now visiting /api/spotify-recently-played will return your latest played track in JSON.


🎨 Step 4 — Create the Spotify Widget

Finally, let’s build the UI. You can grab a starter widget here:

Copy the code into src/components/SpotifyWidget.astro and update the fetch URL if needed.


✅ Wrapping Up

You just built a Spotify Recently Played widget using Astro server endpoints and the Spotify Web API.

This small feature shows that you:

  • Understand OAuth flows
  • Can create secure backend endpoints in Astro
  • Know how to integrate third-party APIs into your projects

It’s a small touch — but one that makes your portfolio more alive and personal.

📚 For more details, check out Spotify’s official Authorization Code Flow guide.

Top comments (0)