Published on July 19, 2026

Most music listeners use more than one streaming service. They have a Spotify account for curated playlists, Apple Music for lossless audio, YouTube Music for live recordings, and maybe Tidal or Deezer for specific catalogs. Their real listening profile lives across all of these platforms.
Building a dashboard that shows a user's combined music stats requires pulling data from each service, normalizing different response formats, and handling authentication for every platform. That is a significant engineering investment when done from scratch.
This tutorial walks through how to build a cross-service music listening stats dashboard using a single API integration. You will learn what data is available, how to fetch and normalize it, and how to display it in a useful way.
A listening stats dashboard built on a single service only shows part of the picture. Users who split their time across Spotify, Apple Music, and YouTube Music get incomplete analytics from any one platform alone.
Cross-service listening data matters for several use cases:
The problem is not a lack of data. Each streaming platform exposes some combination of favorite tracks, play counts, listening history, and user profiles through their APIs. The problem is that each platform returns this data in different formats, through different authentication flows, with different rate limits and permissions.
The specific data points you can pull vary by service. Here is a breakdown of what the major streaming platforms expose through their APIs, and how MusicAPI normalizes access to them.
| Data Type | Spotify | Apple Music | YouTube Music | Tidal | Deezer | SoundCloud |
|---|---|---|---|---|---|---|
| Favorite/liked tracks | Yes | Yes | Yes | Yes | Yes | Yes |
| User playlists | Yes | Yes | Yes | Yes | Yes | Yes |
| User profile | Yes | Yes | Yes | Yes | Yes | Yes |
| Playlist track details | Yes | Yes | Yes | Yes | Yes | Yes |
| Play count (per track) | Limited | No | No | No | No | Yes (public) |
| Full listening history | Recently played only | No | No | No | No | No |
A few things to notice:
For a stats dashboard, your best foundation is favorite tracks and user playlists. These are consistently available across services and give you enough signal to calculate top artists, genre distributions, and cross-platform overlaps.
MusicAPI provides normalized access to favorite tracks, playlists, playlist tracks, and user profiles across all supported services. You write one API call, and the response structure is identical whether the data comes from Spotify, Apple Music, or Tidal.
Without a unified API, fetching a user's favorite tracks from three services means writing three separate integrations. Each one needs its own OAuth flow, its own request format, and its own response parser.
With MusicAPI, the code looks the same for every service. Here is how you fetch favorite tracks from multiple platforms using the same endpoint:
// Authenticate users via MusicAPI's unified OAuth first
// See: https://musicapi.com/docs/user-authentication/getting-started
const services = ['spotify', 'apple_music', 'youtube_music', 'tidal'];
async function getFavoriteTracks(userToken, service) {
const response = await fetch('https://api.musicapi.com/v1/me/favorites/tracks', {
headers: {
'Authorization': `Bearer ${userToken}`,
'X-Music-Service': service
}
});
return response.json();
}
// Fetch from all connected services in parallel
const allFavorites = await Promise.all(
services.map(service => getFavoriteTracks(userToken, service))
);
// Each response has the same normalized structure
// [{ id, title, artist, album, duration, service }, ...]
Notice that the endpoint, headers, and response shape are identical for every service. The only thing that changes is the X-Music-Service header value. This is the core value of a unified music API: you write the integration once and it works across all platforms.
Building a music stats dashboard that pulls from multiple services? MusicAPI handles the OAuth, normalization, and rate limiting so you can focus on the dashboard itself.
Once you have favorite tracks from multiple services, you need to aggregate them into meaningful stats. Here is a practical pipeline that calculates top artists and genre distribution from cross-service data.
// Step 1: Fetch favorites from all connected services
const connectedServices = user.connectedServices; // ['spotify', 'apple_music', 'tidal']
const tracksByService = {};
for (const service of connectedServices) {
const data = await getFavoriteTracks(user.token, service);
tracksByService[service] = data.tracks;
}
// Step 2: Deduplicate tracks across services
// Users often favorite the same song on multiple platforms
function deduplicateTracks(tracksByService) {
const seen = new Map();
const allTracks = [];
for (const [service, tracks] of Object.entries(tracksByService)) {
for (const track of tracks) {
// Create a normalized key: lowercase title + artist
const key = `${track.title.toLowerCase()}::${track.artist.toLowerCase()}`;
if (seen.has(key)) {
// Track exists on multiple services — add the service to its list
seen.get(key).services.push(service);
} else {
const entry = { ...track, services: [service] };
seen.set(key, entry);
allTracks.push(entry);
}
}
}
return allTracks;
}
// Step 3: Calculate artist frequency
function getTopArtists(tracks, limit = 10) {
const artistCounts = {};
for (const track of tracks) {
const artist = track.artist;
artistCounts[artist] = (artistCounts[artist] || 0) + 1;
}
return Object.entries(artistCounts)
.sort(([, a], [, b]) => b - a)
.slice(0, limit)
.map(([artist, count]) => ({ artist, count }));
}
// Step 4: Calculate cross-platform overlap
function getCrossPlatformTracks(tracks) {
return tracks
.filter(t => t.services.length > 1)
.sort((a, b) => b.services.length - a.services.length);
}
// Run the pipeline
const deduplicated = deduplicateTracks(tracksByService);
const topArtists = getTopArtists(deduplicated);
const crossPlatform = getCrossPlatformTracks(deduplicated);
console.log(`Total unique favorites: ${deduplicated.length}`);
console.log(`Top artist: ${topArtists[0].artist} (${topArtists[0].count} tracks)`);
console.log(`Tracks favorited on 2+ services: ${crossPlatform.length}`);
This pipeline produces three key metrics for your dashboard:
The hardest part of building cross-service features is not the business logic. It is getting all the data into the same shape.
Without a unified API, here is what you deal with:
| Field | Spotify Format | Apple Music Format | YouTube Music Format |
|---|---|---|---|
| Track title | track.name | attributes.name | snippet.title |
| Artist name | track.artists[0].name | attributes.artistName | snippet.channelTitle |
| Duration | track.duration_ms (milliseconds) | attributes.durationInMillis | contentDetails.duration (ISO 8601) |
| Album | track.album.name | attributes.albumName | N/A (varies) |
| Track ID | track.id (Spotify URI) | id (catalog ID) | id.videoId |
Every field name is different. Duration formats are inconsistent. Artist data is nested differently. And this is just three services. Add Tidal, Deezer, SoundCloud, Amazon Music, Qobuz, Audiomack, Audius, Boomplay, and Napster, and you are writing dozens of field mappers.
MusicAPI does this normalization for you. Every supported service returns the same response structure:
{
"id": "normalized-id",
"title": "Track Title",
"artist": "Artist Name",
"album": "Album Name",
"duration": 234,
"service": "spotify"
}
Same field names. Same types. Same nesting. Your aggregation code (like the pipeline above) works without any per-service conditionals.
Once your data pipeline is running, you need to present the stats. Here are proven patterns for music listening dashboards.
| Library | Best For | Framework |
|---|---|---|
| Recharts | Simple bar/line charts, quick setup | React |
| Chart.js | Lightweight, canvas-based charts | Framework-agnostic |
| D3.js | Custom, complex visualizations | Framework-agnostic |
| Nivo | Pre-built chart components with themes | React |
| Apache ECharts | Large datasets, interactive charts | Framework-agnostic |
Top Artists Bar Chart: Horizontal bar chart showing the user's top 10 artists by favorite count. Color-code bars by the primary service where each artist was favorited.
Service Distribution Pie Chart: Show what percentage of a user's total favorites come from each streaming service. This tells users where they are most active.
Cross-Platform Overlap Venn Diagram: Visualize tracks that appear on multiple services. Use D3.js or a dedicated Venn library for this.
Timeline View: If you pull playlist data alongside favorites, plot when playlists were created or last modified across services. This shows listening trends over time.
// Example: Recharts data structure for a top artists chart
import { BarChart, Bar, XAxis, YAxis, Tooltip } from 'recharts';
const chartData = topArtists.map(({ artist, count }) => ({
name: artist,
favorites: count
}));
function TopArtistsChart() {
return (
<BarChart width={600} height={300} data={chartData} layout="vertical">
<XAxis type="number" />
<YAxis type="category" dataKey="name" width={120} />
<Tooltip />
<Bar dataKey="favorites" fill="#1DB954" />
</BarChart>
);
}
Fetch data from all services in parallel (as shown in the pipeline example) and cache the normalized results. Most listening stats do not change minute-to-minute. A 15-minute cache keeps your dashboard responsive without hammering the APIs. MusicAPI's rate limiting is already centralized, but caching on your side reduces latency for returning users.
A music listening stats API provides access to user data from streaming platforms: favorite tracks, playlists, play counts, and listening history. Each streaming service has its own API for this data. A unified API like MusicAPI normalizes this data across 12+ services into a single endpoint and response format.
Full listening history is limited. Only Spotify offers a "recently played" endpoint (capped at 50 tracks). Most other services do not expose listening history at all. However, you can build a useful stats dashboard using favorite tracks and playlists, which are available across all major platforms through MusicAPI.
Each streaming service has its own OAuth flow. Building and maintaining these separately takes months. MusicAPI's unified authentication handles OAuth for all supported services through a single flow. Users connect their accounts once, and your app gets a single token that works across platforms.
For React apps, Recharts offers the fastest setup with clean defaults. Chart.js works well for framework-agnostic projects. D3.js gives you full control for custom visualizations like Venn diagrams or force-directed genre graphs. Choose based on your framework and how custom your charts need to be.
Create a normalized key from the track title and artist name (both lowercase). When the same song appears in favorites on multiple services, merge the entries and track which services it appeared on. This deduplication step is critical for accurate stats. The code example in this post demonstrates this pattern.
No. Play count availability varies significantly. Spotify provides limited play count data. SoundCloud exposes public play counts. Most other services (Apple Music, YouTube Music, Tidal, Deezer) do not expose per-user play counts through their APIs. Base your dashboard metrics on favorite tracks and playlists for the most consistent cross-service coverage.
The API costs depend on your scale. MusicAPI offers tiered pricing that starts with a free trial. The real cost savings come from engineering time: building and maintaining 12 separate service integrations takes months. A unified API reduces that to days.
Ready to skip months of OAuth and SDK work? Start your free MusicAPI trial and connect 10+ streaming services with one unified API.