Someone searched our API for YIPPEE-KI-YAY. (The Hosed Down Remix) — a Kesha remix from 2025. We returned nothing. Not "rate limited," not "service down" — just not found.
Here is the uncomfortable part. That track is on Apple Music. It is on Deezer. It is on Spotify. It is in MusicBrainz. Every major music database has it, and our pipeline pulls from those same sources. The track was never missing. Our matching layer — the code that decides "this record and that record are the same song" — couldn't see it.
This is the autopsy: three separate, completely mundane reasons a track that demonstrably exists failed to match, and how we fixed each. If you build anything that reconciles music metadata across sources, you will hit all three.
Matching is the actual hard part
A music API is a stitching job. No single source has everything: iTunes has preview clips, Deezer has wide coverage, MusicBrainz has identifiers and relationships, AcousticBrainz has audio features. You query several sources and you merge the results.
"Merge" hides the hard part. To merge, you first have to decide that Deezer's record and MusicBrainz's record describe the same recording. That decision is "matching," and it sounds like string equality. It is not.
The enemy is simple to state: the same song is written slightly differently in every database. Not wildly — slightly. And "slightly different" is exactly the gap a naive matcher falls straight through.
Failure mode 1 — Punctuation drift
The query was YIPPEE-KI-YAY (The Hosed Down Remix). Deezer's stored title is YIPPEE-KI-YAY. (The Hosed Down Remix). Spot the difference? There is a period after YIPPEE-KI-YAY — Kesha's 2025 album stylises the song with a trailing dot. An exact string compare fails. A substring compare fails too: yay ( is not a substring of yay. (.
It gets better. MusicBrainz stores the same title with typographic hyphens — Unicode U+2010 — where you typed the ASCII hyphen-minus, U+002D. They render identically in almost every font. They are different bytes. Every byte-level comparison between them fails, silently, forever.
Now add lowercase versus title-case ("remix" versus "Remix"), straight versus curly apostrophes, & versus "and", stray brackets, and the iTunes habit of writing Song - X Remix where Deezer writes Song (X Remix). Two records can describe the identical recording and disagree on a dozen characters.
The fix is a normalisation fold: before you compare anything, collapse every string to a canonical form. Lowercase it. NFKD-decompose so accented characters fold to their base (Beyoncé becomes beyonce). Replace every punctuation and dash variant — ASCII hyphen, typographic hyphen, en dash, em dash, the lot — with a space. Collapse runs of whitespace. Then compare.
import unicodedata
# every dash variant folds to one space; punctuation folds away
_DASHES = "-‐‑–—" # ascii, U+2010, U+2011, en, em
_DROP = str.maketrans({c: " " for c in _DASHES + ".,!?'()[]&"})
def fold(s):
s = unicodedata.normalize("NFKD", s) # accents -> base chars
s = "".join(c for c in s if not unicodedata.combining(c))
return " ".join(s.lower().translate(_DROP).split())
Run both titles through fold() and they collapse to the same eight words: yippee ki yay the hosed down remix. A match that was impossible at the byte level is trivial after the fold.
The lesson: never compare provider strings raw. Fold first. Punctuation in a music title carries almost no information and offers infinite room for disagreement.
Failure mode 2 — Your main source's search has blind spots
Our primary resolver is iTunes. It is an enormous, well-curated catalog. So when iTunes search returned zero results for the Hosed Down Remix, the obvious conclusion was "iTunes doesn't have it."
Wrong. iTunes has it. We pulled the track by direct ID lookup — that returns it instantly, with a preview clip, no problem. But the iTunes Search API returned nothing. Searching the song's plain title surfaced fourteen results; the remix was not one of them.
The iTunes Search API is not a window onto the whole iTunes catalog. It is a partial, recency- and popularity-weighted index. New releases, remixes, deluxe-edition cuts and long-tail tracks can be fully present in the store — buyable, previewable, reachable by ID — and simply absent from text-search results. Every catalog API has a version of this. A search surface is never the whole catalog.
Two lessons. First: "search returned nothing" is not "the track does not exist" — it is "this index did not surface it." Don't let one source's blind spot become your final answer. Second: have a fallback source — we use Deezer — and understand that the fallback is now load-bearing. Which means the fallback's matcher had better be solid. Ours wasn't.
Failure mode 3 — "Take the first result" is not a matcher
Here is the cheap way to resolve a track against MusicBrainz: search by title and artist, ask for one result, take recordings[0]. It is one line. It feels fine. We shipped it, and it was wrong in two distinct ways.
It picks silently wrong. recordings[0] trusts MusicBrainz's relevance ranking to put the right recording first. Often it does. When it doesn't — when a live album version, a compilation re-edit or a karaoke cover ranks first — you take that, with full confidence, and never know. An audit we ran put the wrong-recording rate of naive first-result matching at roughly one in seven. One match in seven pointed at a different recording than the one the customer asked about.
And a wrong match is worse than no match. This is the part that matters. If matching returns nothing, you see a null — and a null is honest: "we don't have this." If matching returns the wrong recording, every field you derive from it is now wrong: the release date, the ISRC, the genre, the audio features keyed off that identifier. And it all looks completely plausible. A wrong match does not fail loudly. It quietly poisons the record and everything downstream of it.
The fix is to stop taking the first result and start scoring. Pull a list of candidates — twenty-five, not one. Score each against the query on multiple independent signals:
- Title, folded (see failure mode 1).
- Artist, folded.
- Duration. This is the signal that catches the wrong-cut problem. A studio single and its six-minute live version share a title and an artist; they do not share a length. If a candidate's duration is wildly off the one you expected, it is a different recording — score it down, hard.
def score(candidate, query, expected_ms):
s = 0
if fold(candidate.title) == fold(query.title): s += 10
elif fold(query.title) in fold(candidate.title): s += 5
if fold(candidate.artist) == fold(query.artist): s += 8
if candidate.length_ms and expected_ms:
off = abs(candidate.length_ms - expected_ms)
s += 6 if off < 5000 else -8 # same cut, or a different one
return s
Then — and this is the important rule — only accept a confident match. Set a threshold that requires real corroboration: a title match plus either an artist match or a duration match. A bare title match, with nothing else agreeing, is not enough — far too many songs share a title. If nothing clears the bar, return nothing. Decline to guess. A null you can fix on the next pass; a wrong ID you will never even notice.
The stylised-artist wrinkle. This is also why you cannot lean on any single signal. Deezer returns Kesha's name as
Ke$ha. MusicBrainz saysKesha. The$is not punctuation you can fold away — it is a deliberate substitution. So for this track the artist signal is simply unavailable:ke$haandkeshawill not match however you normalise. The match still succeeds — because the title folds clean and the duration agrees to within a second. Two signals out of three is enough. One never is.
The thread: corroboration beats cleverness
Step back and the three fixes are one idea. Punctuation folding, fallback sources, multi-signal scoring — every one of them is a way of saying: never trust a single signal, and never guess.
A music metadata pipeline has an asymmetric cost structure. A missing value is cheap: it is visible, it is honest, and it gets filled on the next pass. A wrong value is expensive: it is invisible, it looks right, and it spreads. Genre filters return the wrong tracks. ISRC lookups resolve to the wrong release. Audio features get attributed to the wrong recording. None of it throws an error.
So the discipline is conservative by design: fold before you compare, corroborate before you commit, and when the signals disagree, return null and move on. "I don't know" is a perfectly good answer from a metadata API. "Here is a confident wrong answer" is not.
This article was originally published on the FreqBlog blog. FreqBlog runs a music-metadata API that resolves tracks across iTunes, Deezer, MusicBrainz and more.
Top comments (0)