How I Built a “Now Playing” Spotify Widget for My React Portfolio

Hey everyone!

I recently added a neat little feature to my personal portfolio: a Spotify widget that shows what I’m currently listening to. It’s a great way to add a dynamic and personal touch to a site. In this post, I’ll walk you through how I built…


This content originally appeared on DEV Community and was authored by Jefino

Hey everyone!

I recently added a neat little feature to my personal portfolio: a Spotify widget that shows what I'm currently listening to. It’s a great way to add a dynamic and personal touch to a site. In this post, I'll walk you through how I built it using React, a custom hook, and a serverless function to securely communicate with the Spotify API.

Here's a quick look at the final result:

The "Why": Adding a Personal Touch

A portfolio is a reflection of who we are as developers. While showcasing projects is key, adding small, personal elements can make a site more engaging. I love listening to music while I code, so I thought, "Why not share what's currently playing?" This widget does just that, and it also shows off some key development skills like API integration and handling authentication.

The "How": A Three-Part Harmony

The solution can be broken down into three main parts:

  1. A secure backend endpoint to handle the Spotify API keys.
  2. A custom React hook to fetch the data on the frontend.
  3. A UI component to display the track information beautifully.

Let's dive into each part.

Part 1: The Secure Backend (Using a Serverless Function)

You should never expose your API keys or secrets on the frontend. To solve this, I created a serverless function (which you can host on Vercel or Netlify) that acts as a proxy to the Spotify API.

This function does two things:

  1. It uses my Spotify refresh_token to get a temporary access_token.
  2. It then uses that access_token to ask Spotify for my currently playing track. If nothing is playing, it fetches my most recently played track instead.

Here’s a simplified look at the logic from my api/spotify.ts file:

// api/spotify.ts

// 1. Get credentials securely from environment variables
const clientId = process.env.SPOTIFY_CLIENT_ID!;
const clientSecret = process.env.SPOTIFY_CLIENT_SECRET!;
const refreshToken = process.env.SPOTIFY_REFRESH_TOKEN!;

// 2. Request a new access token from Spotify
const tokenResponse = await fetch("https://accounts.spotify.com/api/token", {
    method: "POST",
    headers: {
        Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
        "Content-Type": "application/x-www-form-urlencoded",
    },
    body: new URLSearchParams({
        grant_type: "refresh_token",
        refresh_token: refreshToken,
    }),
});

const { access_token } = await tokenResponse.json();

// 3. Fetch the currently playing track
const nowPlayingRes = await fetch("https://api.spotify.com/v1/me/player/currently-playing", {
    headers: { Authorization: `Bearer ${access_token}` },
});

// 4. If nothing is playing, fetch the most recently played track as a fallback
if (nowPlayingRes.status === 204 || /* ... */) {
    // ... logic to fetch from the 'recently-played' endpoint
}

// 5. Return the track data as JSON
// ...

Part 2: The Custom Hook (useSpotify.ts)

To manage fetching and state on the frontend, I created a custom hook called useSpotify. This hook handles the loading, error, and success states of the API call. It also automatically refetches the data every 30 seconds.

Here's the core fetching logic inside the hook:

// src/hooks/useSpotify.ts
const [track, setTrack] = useState<SpotifyTrack | null>(null);
const [isLoading, setIsLoading] = useState(true);

const fetchSpotifyTrack = useCallback(async () => {
    try {
        // This fetch call goes to OUR serverless function, not directly to Spotify
        const response = await fetch('/api/spotify');

        if (response.ok) {
            const trackData = await response.json();
            setTrack(trackData);
        } else {
            // ... error handling
        }
    } catch (err) {
        // ... error handling
    } finally {
        setIsLoading(false);
    }
}, []);

useEffect(() => {
    // Initial fetch
    fetchSpotifyTrack();
    // Fetch every 30 seconds
    const interval = setInterval(fetchSpotifyTrack, 30000);
    // Cleanup on unmount
    return () => clearInterval(interval);
}, [fetchSpotifyTrack]);

Part 3: The UI Component (SpotifyWidget.tsx)

This is where the magic happens! The SpotifyWidget.tsx component calls our useSpotify hook and renders the UI based on the state. It handles three scenarios:

  1. Loading: Shows a simple "Loading..." state with a spinning animation.
  2. Error/No Music: Displays a "No music" or "Connection error" message.
  3. Success: Shows the track name and an icon indicating if it's currently playing or was recently played.

I used framer-motion to add some slick animations, like a pulsing effect when a song is playing and a hover-to-reveal tooltip with the album art and artist name.

Here's a snippet of the component's rendering logic:

// src/components/SpotifyWidget.tsx
export default function SpotifyWidget() {
    const { track, isLoading, error } = useSpotify(30000);

    if (isLoading) {
        return (/* ... Loading UI ... */);
    }

    if (!track || error) {
        return (/* ... Error/No Music UI ... */);
    }

    return (
        <motion.div /* ... animations ... */>
            <div className="flex items-center ...">
                {track.isPlaying ? <Play /> : <Pause />}
                <div className="truncate ...">{track.name}</div>
                <ExternalLink />
            </div>

            {/* Pulsing effect when playing */}
            {track.isPlaying && <motion.div /* ... */ />}

            {/* Tooltip with more details on hover */}
            <AnimatePresence>
                {showTooltip && (
                    <motion.div /* ... Tooltip UI with album art and artist ... */>
                        {/* ... */}
                    </motion.div>
                )}
            </AnimatePresence>
        </motion.div>
    );
}

Conclusion

And that's it! By separating concerns between the backend, the hook, and the component, we have a clean, secure, and reusable Spotify widget. It's a fun way to make a portfolio more personal and demonstrates practical skills.

You can check out the full source code for this feature in my portfolio's GitHub repository.

Thanks for reading! Let me know what you think in the comments.


This content originally appeared on DEV Community and was authored by Jefino


Print Share Comment Cite Upload Translate Updates
APA

Jefino | Sciencx (2025-08-28T05:16:20+00:00) How I Built a “Now Playing” Spotify Widget for My React Portfolio. Retrieved from https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/

MLA
" » How I Built a “Now Playing” Spotify Widget for My React Portfolio." Jefino | Sciencx - Thursday August 28, 2025, https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/
HARVARD
Jefino | Sciencx Thursday August 28, 2025 » How I Built a “Now Playing” Spotify Widget for My React Portfolio., viewed ,<https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/>
VANCOUVER
Jefino | Sciencx - » How I Built a “Now Playing” Spotify Widget for My React Portfolio. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/
CHICAGO
" » How I Built a “Now Playing” Spotify Widget for My React Portfolio." Jefino | Sciencx - Accessed . https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/
IEEE
" » How I Built a “Now Playing” Spotify Widget for My React Portfolio." Jefino | Sciencx [Online]. Available: https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/. [Accessed: ]
rf:citation
» How I Built a “Now Playing” Spotify Widget for My React Portfolio | Jefino | Sciencx | https://www.scien.cx/2025/08/28/how-i-built-a-now-playing-spotify-widget-for-my-react-portfolio-3/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.