Skip to main content

Music Metadata APIs: Working with ISRCs, Track IDs, and Cross-Platform Matching

Published on July 19, 2026

Music Metadata APIs: Working with ISRCs, Track IDs, and Cross-Platform Matching

Every music streaming platform assigns its own internal ID to every track. The same song by the same artist has a completely different identifier on Spotify than it does on Apple Music, YouTube Music, Tidal, or Deezer. This makes cross-platform matching one of the hardest problems in music app development.

ISRCs (International Standard Recording Codes) were supposed to solve this. In theory, every recording gets a unique 12-character code that works across all platforms. In practice, ISRC data is inconsistent, sometimes missing, and occasionally wrong.

This post explains how music metadata identifiers work, why cross-platform matching is harder than it looks, and how to build reliable matching into your application without maintaining per-service lookup logic.

The Music Metadata Problem: Why Track IDs Differ Across Platforms

Each streaming platform maintains its own content catalog with its own identifier system. When a label or distributor delivers a track to Spotify, Apple Music, and Tidal, each platform ingests it independently and assigns its own internal ID.

Here is the same track across four platforms:

PlatformTrack ID FormatExample
SpotifyBase-62 hash4iV5W9uYEdYUVa79Axb7Rh
Apple MusicNumeric catalog ID1440818231
YouTube Music11-char video IDdQw4w9WgXcQ
TidalNumeric track ID77814764
DeezerNumeric track ID3135556

These IDs have zero overlap. You cannot derive one from another. They are not based on any shared standard. Each platform built its identifier system independently, and there is no universal registry mapping them together.

For developers, this creates three immediate problems:

  1. Playlist migration: Moving a playlist from one service to another requires matching every track by metadata (title, artist, album) since IDs are incompatible.
  2. Cross-platform deduplication: If a user has favorites on both Spotify and Apple Music, determining which tracks overlap requires fuzzy matching or a shared identifier like ISRC.
  3. Content referencing: If your app stores a track reference, you need a mapping layer to resolve that reference across services.

ISRCs, UPCs, and Platform-Specific IDs Explained

The music industry has two standard identifiers designed to work across platforms. Neither is perfect.

ISRC (International Standard Recording Code)

An ISRC is a 12-character alphanumeric code assigned to a specific recording. Format: CC-XXX-YY-NNNNN (country, registrant, year, designation).

Example: USUM71703861 identifies one specific master recording. In theory, this code is the same on every platform that carries that recording.

Where ISRCs work well:

  • Major label releases almost always have ISRCs
  • Most platforms include ISRCs in their API responses (when available)
  • ISRCs identify recordings, not compositions, so different versions of the same song get different ISRCs

Where ISRCs break down:

  • Independent and self-distributed tracks often lack ISRCs entirely
  • Some tracks have multiple ISRCs assigned by different distributors
  • Remastered or re-released versions may share an ISRC with the original (or may not)
  • Regional variants sometimes use different ISRCs for the same recording
  • Not all platform APIs expose ISRCs consistently

UPC (Universal Product Code)

UPCs identify albums/releases, not individual tracks. A 12-digit barcode standard. Useful for matching albums across platforms, but not granular enough for track-level matching.

Platform-Specific IDs

Each platform also maintains additional internal identifiers:

IdentifierPlatformScope
Spotify URISpotifyTrack, album, artist, playlist
Apple Music Catalog IDApple MusicTrack, album, artist
Video IDYouTube MusicTrack (as video)
Tidal Track IDTidalTrack
Deezer Track IDDeezerTrack
SoundCloud Track IDSoundCloudTrack

These are reliable within their own platform but useless for cross-platform matching.

How MusicAPI Handles Metadata Normalization

MusicAPI normalizes metadata from all supported services into a consistent response format. When you fetch track data through MusicAPI, you get the same field names, the same nesting, and the same data types regardless of the source service.

Here is what a normalized track response looks like:

{
  "id": "musicapi-normalized-id",
  "title": "Never Gonna Give You Up",
  "artist": "Rick Astley",
  "album": "Whenever You Need Somebody",
  "duration": 213,
  "isrc": "USUM71703861",
  "service": "spotify",
  "serviceId": "4iV5W9uYEdYUVa79Axb7Rh"
}

Key normalization details:

  • Consistent field names: title, artist, album, duration across all services. No more mapping track.name vs. attributes.name vs. snippet.title.
  • ISRC included when available: MusicAPI passes through the ISRC from the source service, giving you the best cross-platform identifier when it exists.
  • Service and serviceId preserved: You always know which platform the data came from and can reference the original platform-specific ID.
  • Duration standardized: Always in seconds (integer), regardless of whether the source platform uses milliseconds, ISO 8601, or some other format.

This normalization means your cross-platform matching code does not need per-service field mappers. You write one set of matching logic, and it works for data from all 12+ supported services.

Dealing with metadata headaches across multiple music services? MusicAPI normalizes track data, ISRCs, and identifiers from 12+ platforms into one consistent format. No per-service parsing required.

Code Example: Looking Up a Track Across Services by ISRC

Here is a practical pattern for matching a track across services. The approach: use MusicAPI to fetch track data from multiple services, then match using ISRC (when available) or fuzzy metadata matching (as fallback).

// Authenticate via MusicAPI's unified OAuth first
// See: https://musicapi.com/docs/user-authentication/getting-started

const SERVICES = ['spotify', 'apple_music', 'youtube_music', 'tidal', 'deezer'];

// Step 1: Search for a track on all services
async function findTrackAcrossServices(query, userToken) {
  const results = {};

  for (const service of SERVICES) {
    const response = await fetch(
      `https://api.musicapi.com/v1/search/tracks?q=${encodeURIComponent(query)}`,
      {
        headers: {
          'Authorization': `Bearer ${userToken}`,
          'X-Music-Service': service
        }
      }
    );
    const data = await response.json();
    results[service] = data.tracks || [];
  }

  return results;
}

// Step 2: Match by ISRC (strongest signal)
function matchByIsrc(resultsByService) {
  const isrcMap = {};

  for (const [service, tracks] of Object.entries(resultsByService)) {
    for (const track of tracks) {
      if (track.isrc) {
        if (!isrcMap[track.isrc]) {
          isrcMap[track.isrc] = [];
        }
        isrcMap[track.isrc].push({
          service,
          serviceId: track.serviceId,
          title: track.title,
          artist: track.artist
        });
      }
    }
  }

  return isrcMap;
}

// Step 3: Fuzzy fallback for tracks without ISRCs
function fuzzyMatch(track, candidates) {
  const normalize = (str) => str.toLowerCase().replace(/[^a-z0-9]/g, '');
  const targetTitle = normalize(track.title);
  const targetArtist = normalize(track.artist);

  return candidates.filter(candidate => {
    const titleMatch = normalize(candidate.title) === targetTitle;
    const artistMatch = normalize(candidate.artist).includes(targetArtist)
      || targetArtist.includes(normalize(candidate.artist));
    return titleMatch && artistMatch;
  });
}

// Usage
const results = await findTrackAcrossServices('Never Gonna Give You Up Rick Astley', token);
const isrcMatches = matchByIsrc(results);

// isrcMatches['USUM71703861'] contains the track on every service that has the ISRC
console.log(isrcMatches);
// {
//   'USUM71703861': [
//     { service: 'spotify', serviceId: '4iV5W9uYEdYUVa79Axb7Rh', ... },
//     { service: 'apple_music', serviceId: '1440818231', ... },
//     { service: 'tidal', serviceId: '77814764', ... },
//     { service: 'deezer', serviceId: '3135556', ... }
//   ]
// }

This pattern gives you a reliable cross-platform track mapping. ISRC matching is preferred because it is deterministic. Fuzzy matching serves as a fallback for tracks where ISRCs are missing or inconsistent.

Common Pitfalls: Duplicate Tracks, Regional Variants, and Missing Fields

Cross-platform metadata matching has several failure modes that catch developers off guard. Here are the most common ones and how to handle them.

Duplicate ISRCs

Some recordings have multiple ISRCs assigned by different distributors or labels. When this happens, the "same" track may have different ISRCs on different platforms. Your matching logic should:

  • Group by ISRC first, then apply fuzzy matching within each group to catch duplicates
  • Store all known ISRCs for a track, not just the first one you find
  • Treat ISRC as a strong signal, not a guaranteed unique key

Regional variants

Streaming platforms often have different catalog entries for the same recording in different regions. A track available in the US catalog may have a different ID (and sometimes a different ISRC) than the same track in the EU catalog. Handle this by:

  • Normalizing regional characters in track and artist names before matching
  • Accepting partial matches when ISRC and title match but album names differ
  • Treating "Deluxe Edition" and "Standard Edition" tracks as potential matches

Missing metadata fields

Not every platform returns every metadata field for every track. Common gaps:

FieldOften Missing On
ISRCSoundCloud, Audius, Audiomack
Album nameYouTube Music (for singles/videos)
DurationRare, but format varies
Release dateVaries by service
GenreMost platforms (via track endpoint)

Your matching pipeline should handle missing fields gracefully. Do not fail the entire match if one field is null. Instead, weight your confidence score based on which fields are available and matching.

Character encoding and special characters

Artist and track names can contain accents, non-Latin characters, and special characters that render differently across platforms. Always normalize Unicode (NFC normalization), strip diacritics for comparison, and compare lowercase versions.

Building Reliable Cross-Platform Matching into Your App

Here is a battle-tested matching strategy that combines ISRC lookup, fuzzy matching, and confidence scoring.

The matching hierarchy

  1. ISRC match (confidence: 95%+): Same ISRC on both platforms. Strongest signal.
  2. Exact title + artist match (confidence: 85%): Normalized title and artist strings are identical.
  3. Fuzzy title + artist + duration match (confidence: 75%): Title and artist are similar (edit distance < 3) and duration is within 3 seconds.
  4. Fuzzy title + artist only (confidence: 50%): Title and artist match fuzzily, but duration is missing or divergent.
function calculateMatchConfidence(trackA, trackB) {
  let confidence = 0;

  // ISRC match (strongest)
  if (trackA.isrc && trackB.isrc && trackA.isrc === trackB.isrc) {
    confidence = 0.95;
  }

  // Title + artist matching
  const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9\s]/g, '').trim();
  const titleA = normalize(trackA.title);
  const titleB = normalize(trackB.title);
  const artistA = normalize(trackA.artist);
  const artistB = normalize(trackB.artist);

  const titleMatch = titleA === titleB;
  const artistMatch = artistA === artistB
    || artistA.includes(artistB)
    || artistB.includes(artistA);

  if (titleMatch && artistMatch && confidence < 0.85) {
    confidence = 0.85;
  }

  // Duration check (bonus confidence)
  if (trackA.duration && trackB.duration) {
    const durationDiff = Math.abs(trackA.duration - trackB.duration);
    if (durationDiff <= 3 && confidence >= 0.7) {
      confidence = Math.min(confidence + 0.05, 0.98);
    }
  }

  return confidence;
}

Caching your mapping table

Once you match a track across services, cache the mapping. Store tuples of (serviceA_id, serviceB_id, isrc, confidence) so you do not repeat expensive cross-service lookups for tracks you have already matched.

MusicAPI's normalized responses make this caching straightforward because the serviceId field always contains the original platform-specific identifier, and the response format is consistent across all services.

FAQ

What is a music metadata API?

A music metadata API provides structured access to information about songs, albums, and artists: titles, ISRCs, durations, album art, and identifiers. Each streaming platform has its own metadata API. MusicAPI normalizes metadata from 12+ services into one consistent format.

What is an ISRC and how do I use it for matching?

An ISRC (International Standard Recording Code) is a 12-character code that uniquely identifies a sound recording. Format: CC-XXX-YY-NNNNN. Use ISRCs to match the same track across different streaming platforms. Most major label tracks have ISRCs; independent releases may not. MusicAPI includes ISRCs in normalized responses when the source platform provides them.

Why do the same songs have different IDs on different platforms?

Each streaming platform maintains its own content catalog and assigns internal IDs independently. There is no shared registry. A label delivers the same track file to each platform, and each platform creates its own database entry with its own identifier. This is why cross-platform matching requires either ISRCs or fuzzy metadata comparison.

How accurate is ISRC-based track matching?

ISRC matching is the most reliable method, with 95%+ accuracy for major label content. However, ISRCs can be inconsistent: some tracks have multiple ISRCs from different distributors, remastered versions may share ISRCs with originals, and independent releases often lack ISRCs entirely. Always combine ISRC matching with a fuzzy metadata fallback.

Can I match tracks across all streaming services with one API?

Yes. MusicAPI normalizes track data from Spotify, Apple Music, YouTube Music, Tidal, Deezer, SoundCloud, and more into one response format. You can search for a track across all services through the same endpoint and use ISRCs or normalized metadata for matching.

What metadata fields are available across platforms?

Title, artist, album, and duration are available on nearly every platform. ISRCs are available on most major platforms but may be missing on SoundCloud, Audius, and Audiomack. Genre data is inconsistent across services. MusicAPI's supported features page shows exactly which fields are available per service.

How do I handle tracks that exist on one platform but not another?

Regional licensing restrictions mean some tracks are available in one country's catalog but not another. Your matching logic should handle "no match found" as a valid outcome, not an error. Track the match result per service and surface availability information in your UI so users understand why a track is missing.


Ready to skip months of OAuth and SDK work? Start your free MusicAPI trial and connect 10+ streaming services with one unified API.