Spotify Statistic

Building a Real-time Spotify Stats Dashboard with Next.js & SSE
The Challenge
Every music lover is curious about their listening habits, but many third-party apps require extensive permissions and can be slow to update. My goal was to create a personal dashboard that could show real-time listening activity. This presented three core challenges:
- Real-time Data: The official Spotify API does not support WebSockets or Webhooks for real-time playback updates. The most obvious solution, short polling, is inefficient and resource-intensive.
- Credential Security: The Spotify API
client_id
andclient_secret
must be kept secure. Exposing them on the client-side is not an option. - Infrastructure Cost: Building a traditional dedicated backend server just for this personal project would be overkill and costly.
The Solution
I architected a solution using Next.js as a full-stack framework. The key was to leverage Next.js API Routes to create a lightweight, serverless backend that acts as a secure proxy to the Spotify API. For the real-time component, I opted for Server-Sent Events (SSE) to create a persistent, one-way connection that efficiently pushes data from my server to the client without the overhead of constant polling.
Technical Architecture
Next.js API Route as a Secure Proxy
The entire backend logic lives within the /app/api
directory in my Next.js project. This serverless function handles the complex OAuth 2.0 flow and all communication with the Spotify API. The client-side application never interacts with Spotify directly; it only talks to my API route. To solve the real-time data problem, I created an API route that establishes an SSE connection. The server polls the Spotify API internally at a reasonable interval.
// /app/api/spotify-data/route.ts
// A simplified example of the proxy endpoint
export async function GET(req: Request) {
try {
const interval = 5000
const stream = new ReadableStream({
start(controller) {
const intervalId = setInterval(async () => {
const datasource = await spotifyData()
const data = `data: ${JSON.stringify(datasource)}\n\n`
controller.enqueue(new TextEncoder().encode(data))
}, interval)
req.signal.onabort = () => {
clearInterval(intervalId)
controller.close()
}
},
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
},
})
} catch (error) {
// using axios to fetching spotify data
const data = error instanceof AxiosError ? error.response?.data : undefined
const message = error instanceof AxiosError ? error.message : error
const statusCode = error instanceof AxiosError ? error.response?.status || 500 : 500
return new NextResponse(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' }, status })
}
}
Results
The implementation achieved:
- Secure Authentication: Spotify API credentials are never exposed to the client.
- Real-time Experience: The UI updates automatically within seconds of a song change.
- Efficient Architecture: A single, persistent SSE connection replaces dozens of inefficient polling requests from the client.
- Zero Infrastructure Cost: The entire application is deployed on Vercel's free tier, leveraging their serverless function capabilities.
Technical Challenges Overcome
Managing the OAuth 2.0 Flow
Handling Spotify's authentication, especially the process of obtaining and using refresh tokens to request new access tokens on the server-side, was a key challenge that required careful state management.
Graceful Connection Handling
Ensuring the SSE connection was stable, handled errors gracefully, and terminated properly when the user closed the browser tab was crucial to prevent memory leaks and orphaned server processes.
API Rate Limiting
The backend proxy was designed to be mindful of Spotify's API rate limits, ensuring my server-side polling was frequent enough to feel "real-time" but not so frequent as to get blocked.
Conclusion
This project was a deep dive into building a modern, serverless, real-time web application. It demonstrates how Next.js API Routes can be leveraged to create powerful, secure, and cost-effective backends without leaving the comfort of the React ecosystem.
One of the most valuable takeaways came from a limitation: the Spotify API doesn't support real-time updates. At first, I considered short polling, making the client repeatedly ping the server. It worked, but it was inefficient. That's when I discovered Server-Sent Events (SSE), and it completely shifted how I approach data flow and resource management. I learned that there is no perfect solution in the backend, only trade-offs. The success of this implementation proves that by understanding those trade-offs, we can architect elegant solutions to complex problems.