How to display "Spotify now playing" in realtime on your Framer website
I built a Framer override that shows the songs you're playing on your website. Here's how you can do that using a serverless function.
I launched my new portfolio over the weekend - https://chiefpriest.design and I wanted to spice things up and add a music widget that shows anything I’m listening to at the moment.
So I’m sharing this with you guys so you can do the same on yours. You need some basic technical knowledge to set this up but I’ll try to make it as simple as possible.
Lets start with the logic:
You play music on your Spotify
Website checks your Vercel API every 5 seconds
Vercel asks Spotify for permission (using refresh token)
Vercel asks "What's playing right now?"
Spotify answers:
If playing: Show song name and artist
If not playing: Show "No song playing"
Repeat every 5 seconds
What You Need
A Spotify account
A Framer website
A Vercel account (free)
A GitHub account (free)
Step 1: Set Up Spotify
Log in with your Spotify account
Click "Create an App"
Name it anything (like "My Website Music")
Add this Redirect URI: https://localhost:3000/callback
Save your Client ID and Client Secret for later
Step 2: Get Your Refresh Token
Replace YOUR_CLIENT_ID in this link and visit it:
https://accounts.spotify.com/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=https://localhost:3000/callback&scope=user-read-currently-playing%20user-read-playback-state&show_dialog=true
Click 'Agree' on the Spotify page
Copy the code from the new URL (everything after
code=
)Create a new folder on your computer and add this file or clone on github:
// get-token.js
const fetch = require('node-fetch');
async function getRefreshToken() {
const clientId = 'YOUR_CLIENT_ID';
// Add your Client ID here
const clientSecret = 'YOUR_CLIENT_SECRET';
// Add your Client Secret here
const code = 'YOUR_CODE';
// Add your code from step 3 here
try {
const response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64')
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: 'https://localhost:3000/callback'
})
});
const data = await response.json();
console.log('Your refresh token is:', data.refresh_token);
} catch (error) {
console.error('Error:', error);
}
}
getRefreshToken();
Open terminal in that folder and run:
npm init -y
npm install node-fetch
node get-token.js
Save the refresh token it shows you
Step 3: Create Your API
You can clone my Serveless API repo here - Spotify Serveless API or just follow up with the tutorial to create it on your local machine.
Create a new folder called spotify-api
Inside it, create a folder called api
In the api folder, create now-playing.ts with this code:
export const config = {
runtime: 'edge'
};
export default async function handler(request: Request) {
try {
// Get 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 ${btoa(
`${process.env.SPOTIFY_CLIENT_ID}:${process.env.SPOTIFY_CLIENT_SECRET}`
)}`
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: process.env.SPOTIFY_REFRESH_TOKEN
})
});
const { access_token } = await tokenResponse.json();
// Get current song
const response = await fetch('https://api.spotify.com/v1/me/player/currently-playing', {
headers: {
Authorization: `Bearer ${access_token}`
}
});
if (response.status === 204) {
return new Response(JSON.stringify({ isPlaying: false }), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
const data = await response.json();
return new Response(JSON.stringify({
isPlaying: data.is_playing,
title: data.item?.name || '',
artist: data.item?.artists[0]?.name || ''
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
} catch (error) {
return new Response(JSON.stringify({ error: 'Error fetching song' }), {
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
}
Step 4: Deploy to Vercel
Create a new repository on GitHub
Upload your code to the repository
Go to Vercel
Create a new project from your GitHub repository
Add these Environment Variables:
SPOTIFY_REFRESH_TOKEN (from Step 2)
SPOTIFY_CLIENT_ID (from Step 1)
SPOTIFY_CLIENT_SECRET (from Step 1)
Deploy and copy your Vercel URL
Step 5: Add to Your Framer Site
In your Framer project, add a new Code override
Add this code (replace the URL with your Vercel URL):
import type { ComponentType } from "react"
import { useEffect } from "react"
import { createStore } from "https://framer.com/m/framer/store.js@^1.0.0"
const useStore = createStore({
currentSong: "Loading..."
})
export function withSpotifyNowPlaying(Component): ComponentType {
return (props) => {
const [store, setStore] = useStore()
useEffect(() => {
const getCurrentSong = async () => {
try {
const response = await fetch('YOUR_VERCEL_URL/api/now-playing')
const data = await response.json()
if (!data.isPlaying) {
setStore({ currentSong: "No song playing" })
return
}
setStore({ currentSong: `${data.title} - ${data.artist}` })
} catch (error) {
setStore({ currentSong: "Unable to fetch song" })
}
}
getCurrentSong()
const interval = setInterval(getCurrentSong, 5000)
return () => clearInterval(interval)
}, [])
return <Component {...props} text={store.currentSong} />
}
}
export const NowPlaying = withSpotifyNowPlaying(Text)
Write some text and select it, then add your override to it - Note this doesn’t show on the canvas, only on preview.
Another clever way to handle when a song is not playing is to arrange it the same way mine is arranged and change the “No song playing” to “nothing at the moment” or any text that blends in with your static text so it blends in.
Feel free to ask any questions and I’ll be in touch.
Happy Building
See why I've wanted you to come back. Thank you so much Micheal