Identify music in Instagram Reels and TikTok videos
Pass a social-media video URL straight to AudD's recognition endpoint to identify the music in a Reel, TikTok, or YouTube Short — no downloading required.
This recipe identifies the music in a social-media video — an Instagram Reel, a TikTok, a YouTube Short — given only the page URL. You don’t download the video or extract its audio: you hand the URL to AudD, the server fetches and parses it, and you get back the track. It’s for anyone building a “find this sound” feature on top of social content.
What you’ll build
A backend endpoint — POST /identify-url — that accepts a social-media video
URL, passes it straight to AudD’s standard recognition endpoint as the url
parameter, and returns the matched track with streaming links. The thing to
know: AudD parses the social URL server-side and extracts the audio for
you. You never run yt-dlp, store a video file, or touch the platform’s
media servers yourself.
We’ll use the official Node SDK (@audd/sdk), then cover the cases that
matter in practice: videos that are private, removed, or geo-restricted, and
when a long video needs the enterprise endpoint instead.
Prerequisites
- An API token from dashboard.audd.io. The
testtoken (10 requests/day, standard endpoint only) works for first runs. - Node.js 20+ with the official SDK:
npm install @audd/sdk express - A few public social video URLs to test against.
Walkthrough
Step 1: Pass a URL straight to recognize
The standard endpoint’s url parameter accepts a media URL or a
social-media page URL. When you pass a TikTok / Reel / Short page URL, AudD
resolves it server-side, pulls the audio, and fingerprints it. From your
code, it’s the same recognize call you’d use for an audio file.
import { AudD } from "@audd/sdk";
// get a real token at dashboard.audd.io; "test" is capped at 10 req/day
const audd = new AudD("test");
const song = await audd.recognize(
"https://www.tiktok.com/@user/video/1234567890123456789",
{ returnMetadata: ["apple_music", "spotify"] },
);
if (song) {
console.log(`${song.artist} — ${song.title}`);
console.log("Apple Music:", song.streamingUrl("apple_music"));
console.log("Universal link:", song.songLink);
} else {
console.log("no music recognized in this video");
}
The same shape works for an Instagram Reel URL
(https://www.instagram.com/reel/…) or a YouTube Short
(https://www.youtube.com/shorts/…). You pass the page the user copied from
their browser or the share sheet — nothing else.
You don’t download the video. Don’t reach for
yt-dlp,ffmpeg, or a headless browser to grab the file first. Passing the page URL asurllets AudD’s servers do the fetch and audio extraction. Downloading it yourself adds infrastructure, may break the platform’s terms, and gains you nothing.
Step 2: Wrap it in an endpoint
Expose it as an HTTP endpoint your app or extension can call with a pasted URL.
import express from "express";
import { AudD } from "@audd/sdk";
const app = express();
app.use(express.json());
const audd = new AudD(process.env.AUDD_API_TOKEN ?? "test");
app.post("/identify-url", async (req, res) => {
const { url } = req.body as { url?: string };
if (!url) return res.status(400).json({ error: "missing_url" });
const song = await audd.recognize(url, {
returnMetadata: ["apple_music", "spotify"],
});
if (!song) {
// Successful call, nothing recognized — NOT an error.
return res.json({ matched: false });
}
res.json({
matched: true,
artist: song.artist,
title: song.title,
album: song.album,
songLink: song.songLink,
appleMusic: song.streamingUrl("apple_music"),
spotify: song.streamingUrl("spotify"),
});
});
app.listen(8080, () => console.log("listening on :8080"));
A successful call that recognizes nothing resolves to null, which you
surface as { matched: false }. That happens for genuine reasons — the video
has no music, the music isn’t in the database, or AudD couldn’t reach the
video (more on that next). It is never a crash.
Step 3: Handle videos AudD can’t reach
Social videos disappear and lock down constantly: a Reel goes private, a TikTok is removed, a Short is age-gated or geo-restricted in the region AudD’s servers fetch from. These surface in one of two ways, and you handle both gracefully:
- No match — AudD reached the page but couldn’t extract usable audio.
recognizeresolves tonull. Same path as “no music recognized.” - Invalid request — the URL was malformed or AudD couldn’t resolve it to
a fetchable video at all. The SDK raises
AudDInvalidRequestError.
import { AudDInvalidRequestError } from "@audd/sdk";
app.post("/identify-url", async (req, res) => {
const { url } = req.body as { url?: string };
if (!url) return res.status(400).json({ error: "missing_url" });
try {
const song = await audd.recognize(url, {
returnMetadata: ["apple_music", "spotify"],
});
if (!song) {
return res.json({ matched: false, reason: "no_music_found" });
}
res.json({ matched: true, artist: song.artist, title: song.title, songLink: song.songLink });
} catch (err) {
if (err instanceof AudDInvalidRequestError) {
// private, removed, geo-restricted, or an unparseable URL
return res.json({ matched: false, reason: "video_unavailable" });
}
throw err;
}
});
From the user’s point of view, both no_music_found and video_unavailable
collapse to “we couldn’t identify a song in that video” — but keeping them
distinct in your logs tells you whether you’re seeing dead links or genuinely
music-free clips.
Step 4: Use the universal link when a provider is missing
Short-form videos often use trending or regional tracks that aren’t on every
service. When a specific provider link comes back empty, fall back to
song.songLink — the universal lis.tn URL that’s present on every match
and redirects the user to a service they have.
const open = song.streamingUrl("apple_music") ?? song.songLink;
song.streamingUrls() returns every provider link AudD could resolve, which
is handy if you’d rather show all available options than pick one.
When to reach for the enterprise endpoint
The standard endpoint returns one match — the most prominent song it
recognizes. That’s exactly right for a typical Reel or TikTok built around a
single sound. But two situations call for the enterprise endpoint
(POST https://enterprise.audd.io/) instead:
- Longer videos. A multi-minute YouTube video or a long-form upload may run past what a single short-clip recognition covers. The enterprise endpoint chunks the audio server-side and recognizes across the whole thing.
- Multiple songs in one video. A montage, a mashup, or a DJ-set clip can contain several tracks. Enterprise returns one match per recognized segment, with offsets, so you get the full tracklist.
const matches = await audd.recognizeEnterprise(
"https://www.youtube.com/watch?v=SOME_LONG_VIDEO",
{ limit: 25, returnMetadata: ["apple_music"] },
);
for (const m of matches) {
console.log(m.timecode, m.artist, "—", m.title);
}
Always set
limitduring development. The enterprise endpoint bills per 12 seconds of audio processed. An unbounded call on a long video can ingest its entire duration. Start withlimit=25and raise it only once you understand the cost on your real inputs.
Note that the test token does not work on the enterprise endpoint — it’s
standard-endpoint only. You need a real token from the dashboard for
recognizeEnterprise.
What you get back
On the standard endpoint, you get the single top match. With
returnMetadata: ["apple_music", "spotify"] the underlying response looks
like:
{
"status": "success",
"result": {
"artist": "Imagine Dragons",
"title": "Warriors",
"album": "Smoke + Mirrors (Deluxe)",
"release_date": "2015-02-17",
"label": "KIDinaKORNER/Interscope Records",
"timecode": "00:31",
"song_link": "https://lis.tn/Warriors",
"apple_music": { "url": "https://music.apple.com/…", "…": "…" },
"spotify": { "external_urls": { "spotify": "https://open.spotify.com/…" }, "…": "…" }
}
}
| Field | Meaning |
|---|---|
artist, title, album | The recognized track. |
release_date, label | Release date and label of the recording. |
timecode | Position within the matched song at the recognition point — not an offset into the video. |
song_link | Universal lis.tn URL, always present on a match. Your fallback when a specific provider link is missing. |
apple_music, spotify, … | Per-provider blocks, present only for providers you named in returnMetadata. |
On the enterprise endpoint each match additionally carries score,
start_offset, and end_offset (seconds into the video where the match
begins and ends), so you can label which song plays when.
For anything the SDK doesn’t model as a typed property, read
song.extras["the_key"], or song.rawResponse for the full payload.
Handling errors
The cases that matter for this recipe:
- No match (
null) — AudD reached the video but found no recognizable music. Not an error. - Invalid request (
AudDInvalidRequestError) — the URL was malformed, or the video is private, removed, or unreachable. Treat as “video unavailable,” not a server crash. - Authentication / quota (
AudDAuthenticationError,AudDQuotaError) — bad token or exhausted requests. Fix the token or top up at the dashboard; remembertestis capped at 10 requests/day. - Connection (
AudDConnectionError) — transient. The SDK already retries pre-upload connection failures with backoff.
import {
AudDInvalidRequestError,
AudDAuthenticationError,
AudDQuotaError,
AudDAPIError,
} from "@audd/sdk";
try {
const song = await audd.recognize(url, { returnMetadata: ["apple_music"] });
// …
} catch (err) {
if (err instanceof AudDInvalidRequestError) {
return res.json({ matched: false, reason: "video_unavailable" });
} else if (err instanceof AudDAuthenticationError) {
return res.status(500).json({ error: "server_misconfigured" });
} else if (err instanceof AudDQuotaError) {
return res.status(429).json({ error: "quota_exhausted" });
} else if (err instanceof AudDAPIError) {
console.error(`AudD #${err.errorCode}: ${err.serverMessage} (request_id=${err.requestId})`);
return res.status(502).json({ error: "recognition_failed" });
}
throw err;
}
Going further
- Identify music from the microphone instead of a URL. If your users want to identify a song playing around them rather than one in a posted video, see Build a Shazam-style music identification app.
- Full tracklists and copyright checks. To get every song in a longer upload — for a content-ID or moderation use case — see Build a copyright scanner for user-uploaded content.
- Choosing an endpoint. For the full standard-vs-enterprise decision, read Standard, enterprise, or streams: how to choose.
Related
Reading this as an AI agent? The raw Markdown is at recipes/instagram-tiktok-music-id.md, and the full index is /resources/llms.txt.
