---
title: "How to extract music metadata from audio using an API"
description: "A developer guide to extracting structured music metadata — artist, title, album, label, ISRC, and streaming links — from audio files, URLs, and live streams using AudD's recognition API and SDKs."
slug: "/resources/articles/extract-music-metadata-api"
section: "articles"
keywords: [audd, music metadata, audio fingerprinting, isrc, metadata extraction, recognition api]
---

# How to extract music metadata from audio using an API

Music metadata extraction turns raw audio into structured, usable
information. A discovery app, an airplay tracker, and a library manager all
start the same way: resolve the audio to a recording, then read its fields.

This guide covers how to implement music metadata extraction with AudD's
recognition API and its official SDKs, from basic song identification to richer
fields like ISRC codes and label data.

## What is music metadata, and why does it matter?

Music metadata is everything descriptive about a track beyond the audio itself:
the obvious fields (artist, title, album) plus release dates, label, and
industry identifiers used for licensing and royalty tracking.

Developers extract metadata for a range of reasons:

- **Content identification** — automatically tag unknown audio in media
  libraries or user uploads.
- **Copyright compliance** — verify licensing and track usage for reporting.
- **User experience** — display accurate information about whatever's playing.
- **Analytics** — monitor radio airplay, playlist trends, or content over time.
- **Discovery** — power search and recommendation features.

The hard part is accuracy and coverage. AudD's
recognition is neural-network audio fingerprinting against a public database of
160 million songs, which is what determines whether an obscure or recent
track resolves at all.

## What metadata fields can you get?

A basic match returns the core fields. The rest you opt into.

### Always present on a match

- **Title** — the official song name.
- **Artist** — the primary performer or band.
- **Album** — the release or single.
- **Release date** — when the recording was published.
- **Label** — record company or distributor.
- **Timecode** — the position *within the matched song* where your clip
  occurred.
- **`song_link`** — a universal `lis.tn` URL that redirects to the song on the
  user's preferred service.

### On request (`return_metadata`)

Ask for per-provider blocks and AudD returns the matching track object from each
service you name: `apple_music`, `spotify`, `deezer`, `musicbrainz`.
Each provider you request adds a little latency, so ask only for the ones you
render. The provider blocks are where artwork URLs and direct streaming links
live.

### On the Startup plan and higher

- **ISRC** — International Standard Recording Code, a unique identifier per
  recording.
- **UPC** — Universal Product Code for the release.
- **`score`** — the match confidence.

These three are gated to the Startup plan and above; on lower plans they're
simply absent from the response, which is normal and not an error.

## Extraction methods

### From an audio file

Send a file to the standard endpoint and get the top match back. The SDK
accepts a path, raw bytes, a URL, or a file object, so you don't assemble the
HTTP request yourself.

```python
from audd import AudD

# get your own token at dashboard.audd.io; "test" is capped at 10 requests/day
audd = AudD("test")

song = audd.recognize("song.mp3", return_metadata=["apple_music", "spotify"])

if song is None:
    print("no match")
else:
    print("Title:", song.title)
    print("Artist:", song.artist)
    print("Album:", song.album)
    print("Label:", song.label)
    print("Apple Music:", song.streaming_url("apple_music"))
```

`recognize` returns `None` on a successful call that matched nothing — a quiet
clip, a track not in the catalog, or audio that's mostly speech. That's a normal
outcome, distinct from an error.

### From a URL

When the audio is already hosted online, pass the URL instead of uploading
bytes. This avoids the transfer overhead entirely — useful for streaming content
or web-based players.

```javascript
import { AudD } from "@audd/sdk";

const audd = new AudD(process.env.AUDD_API_TOKEN ?? "test");

const song = await audd.recognize("https://audd.tech/example.mp3", {
  returnMetadata: ["apple_music", "spotify", "deezer"],
});

if (song) {
  console.log({
    title: song.title,
    artist: song.artist,
    album: song.album,
    label: song.label,
    releaseDate: song.releaseDate,
    appleMusic: song.streamingUrl("apple_music"),
    spotify: song.streamingUrl("spotify"),
  });
}
```

Prefer the typed helpers (`streamingUrl(...)`, `songLink`) over reaching into
raw provider blocks by hand — they fall back to the universal `lis.tn` link when
a specific provider block is absent.

### From a live stream

Live audio is a continuous-monitoring problem, not a one-off request. Rather
than polling a stream URL yourself, register the source once and let AudD push
matches to you. Use the **streams** mode: `addStream` registers a 24/7 source,
and matches arrive by callback or longpoll as songs change. That's the right
tool for a radio "now playing" display or live-event tracking — it reports each
new track without you managing a recognition loop.

## Reading fields the SDK doesn't model

AudD occasionally returns fields beyond the SDK's typed surface (beta or
undocumented metadata). You don't need a new SDK release to read them.

In Python, the result is a Pydantic model, so any extra field lands in
`model_extra`:

```python
song = audd.recognize("song.mp3")
if song:
    extra_value = song.model_extra.get("some_new_field")
```

In Node, the same fields are on `extras`:

```javascript
const song = await audd.recognize("https://audd.tech/example.mp3");
const extraValue = song?.extras["some_new_field"];
```

This is the supported way to read undocumented or just-shipped fields — the
typed properties cover the common ones, and `model_extra` / `extras` covers
everything else.

## Identifying every song in a longer file

The standard endpoint returns one match. For audio that contains many songs —
a DJ set, a podcast, an archived broadcast — use the **enterprise** endpoint,
which chunks the file and returns *every* match with timestamps, billed per 12
seconds of audio.

```python
matches = audd.recognize_enterprise("long-mix.mp3", limit=10)
for m in matches:
    print(m.timecode, m.artist, "—", m.title)
```

Set a `limit` during development so a long file doesn't expand into more billed
work than you intend.

## Audio formats and recognition quality

AudD accepts common formats — MP3, WAV, M4A/AAC, FLAC, OGG, and more — and
decodes them server-side, so you don't need to transcode. A few inputs help:

- **Bitrate** — higher bitrates carry more of the signal the fingerprinter uses.
- **Clip length** — a short clip is enough for the standard endpoint, which
  analyzes up to about 12 seconds of audio; within that range more audio
  generally helps accuracy, while a much longer file mostly adds upload size and
  latency.
- **Background noise** — cleaner audio matches more reliably.

You generally don't need to preprocess. If you're working with very long source
files, trimming to a representative clip before sending to the standard endpoint
keeps you under its ~10 MB cap; for whole-file analysis, reach for the
enterprise endpoint instead.

## Error handling

Separate three outcomes that are easy to conflate:

- **No match** — `recognize` returns `None`/`null`. Not an error. Retry with a
  different segment, or surface "try again."
- **Errors the server returns** — a bad token, exhausted quota, or undecodable
  audio. The SDKs raise typed exceptions you can branch on (authentication,
  quota, invalid audio, generic API error, connection error).
- **Transient connection failures** — the SDK retries these before your bytes
  reach the server, but never re-sends a recognition call after the upload
  completed, to avoid double-billing.

```python
from audd import (
    AudDAuthenticationError,
    AudDQuotaError,
    AudDInvalidAudioError,
    AudDAPIError,
)

try:
    song = audd.recognize("song.mp3")
except AudDAuthenticationError:
    ...  # bad/missing token — a config problem
except AudDQuotaError:
    ...  # out of requests — top up at dashboard.audd.io
except AudDInvalidAudioError:
    ...  # the bytes weren't decodable audio
except AudDAPIError as e:
    ...  # other server-side error; e.error_code / e.server_message
```

## Matching against your own catalog

Public-catalog recognition answers "what song is this?" If you instead need "is
this *my* track?" — leak detection, sample reuse, matching against unreleased
masters — upload your recordings to a private **custom catalog**. You assign each
uploaded track an integer `audio_id`; later recognition calls match incoming
audio against your tracks and return that `audio_id` (with `artist`/`title`
often `null`, since your private track has no public-catalog metadata). The
upload endpoint is provisioned on request — email api@audd.io.

## Wrapping up

A good recognition API turns metadata extraction from a hard engineering problem
into a manageable integration. Pick the mode that matches your audio — standard
for a short clip, enterprise for a long file, streams for a live source — ask
only for the metadata you render, parse responses leniently, and resolve
anything outside the typed surface through `model_extra` / `extras`.

Get a token at [dashboard.audd.io](https://dashboard.audd.io) and read the
[API reference](https://docs.audd.io) to start.

---

**Related**

- [Result fields reference](/resources/reference/result-fields)
- [Provider metadata reference](/resources/reference/provider-metadata)
- [Standard, enterprise, or streams: how to choose](/resources/concepts/standard-vs-enterprise-vs-streams)
- [API reference](https://docs.audd.io)