How to identify music in live audio streams using an API
Identify songs in live radio and audio streams with AudD: register a stream once and receive every match by webhook or longpoll, or capture and send clips yourself when you can't hand over a URL. Architecture, code, formats, reliability, and cost.
Identifying music in a live stream is different from identifying a song in an uploaded file. Instead of one clip and one answer, you have continuous audio that needs to be recognized around the clock, every track logged with a timestamp, without you babysitting the process.
There are two clean ways to do this with AudD, and choosing the right one up front saves a lot of work:
- Stream recognition (recommended). If your audio is reachable at a URL — an Icecast or HLS feed, which is what most internet radio already publishes — you register the stream once and AudD recognizes it continuously, pushing each match to you. You don’t capture, buffer, or segment anything.
- Capture-and-send. If the audio only exists locally — a microphone, a line input, a feed you can’t expose as a URL — you capture short clips yourself and send each one to the standard recognition endpoint.
Most radio stations, broadcast networks, and streaming platforms fall into the first case, and it is dramatically less code. Reach for capture-and-send only when you genuinely can’t give AudD a URL.
Stream recognition: the recommended path
With stream recognition you register the station’s live audio once and tell AudD where to send results. From then on AudD fingerprints the feed continuously and reports every match — you just receive them.
You get matches two ways, and longpoll is always available alongside callbacks as the alternative:
- Webhook callback. AudD POSTs each match to a URL you control.
- Longpoll. Your backend holds a request open and AudD returns matches as they happen — use it when you’d rather pull than expose a public endpoint.
Register the stream
Add the station’s feed as a stream and set the callback URL that should receive results:
# Register where matches should be POSTed
curl https://api.audd.io/setCallbackUrl/ \
-F api_token=your-api-token \
-F url=https://your-server.example/webhook
Each stream gets its own id, so when you monitor several stations you always know which one a match came from. Request the metadata you need (for example Apple Music and Spotify links) so every result arrives report-ready.
Receive results
Stand up an endpoint to accept matches. Parse leniently — any field can be null — and never throw on a missing field:
from flask import Flask, request
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def on_match():
data = request.json or {}
result = data.get("result")
if result:
record_play(
stream_id=data.get("stream_id"),
title=result.get("title"),
artist=result.get("artist"),
played_at=result.get("timestamp"),
)
return "", 200
That is the whole recognition layer. AudD handles capture, buffering, and segmentation server-side; your job is to receive matches and do something useful with them.
Build a small pipeline around the results
The interesting engineering is downstream of recognition, not inside it:
Deduplicate. A single track produces several consecutive recognitions, and stations repeat songs. Collapse consecutive matches of the same song into one play (or increment a count) rather than logging every fingerprint hit.
Enrich. Join matches to your internal library, chart data, or genre tags as needed.
Process asynchronously. Put incoming matches on a queue so a slow downstream write never blocks ingestion during busy programming.
Store and surface. Persist plays with timestamps and full metadata, then expose them to now-playing displays, airplay reports, and analytics.
Capture-and-send: when you can’t hand over a URL
If the audio lives somewhere AudD can’t reach — a microphone, a sound-card input, an internal feed — you capture short clips and send each one to the standard endpoint yourself. Use the official SDK rather than building raw HTTP requests; it handles the upload format and parses the response for you.
The standard endpoint takes a short clip — it analyzes up to about 12 seconds of audio, and within that range more distinctive audio generally helps; keep uploads small — and returns the single best match. So the pattern is: capture a few seconds, send it, handle the result, repeat.
from audd import AudD
# Get a token at dashboard.audd.io
client = AudD(api_token="your-api-token")
def recognize_clip(path_or_url):
result = client.recognize(path_or_url)
if result:
print(f"Identified: {result.artist} - {result.title}")
else:
# No match — likely speech, an ad, silence, or audio not in the catalog
print("No match")
A few practical points for this path:
- Segment with overlap. Send clips on a sliding window with some overlap so a song that starts mid-segment still gets caught. More overlap means better coverage and more requests — tune it to your needs.
- Standard billing is per request. Each clip you send is one request, so your cost scales with how often you recognize. Recognize on a sensible interval rather than continuously.
- You own reliability. Connection drops, retries, and backoff are yours to handle here, because you’re the one making the calls.
If you find yourself rebuilding continuous capture, buffering, and 24/7 reliability around this path, that’s the signal to switch to stream recognition — it already solves all of it.
Handling different stream formats
HTTP audio streams (Icecast, HLS). This is what most internet radio publishes, and it’s exactly what stream recognition consumes — give AudD the URL and you’re done. If you’re going the capture-and-send route instead, handle connection drops and format changes yourself.
Professional broadcast transports (e.g. RTP). If you only have a transport that AudD can’t pull directly, terminate it into a standard stream URL (Icecast/HLS) first, then register that — or decode it locally and use capture-and-send.
Device input. Microphones and line inputs can’t be handed to AudD as a URL, so they always use capture-and-send. Keep a consistent sample rate and handle device disconnects.
Over-the-air signal. If all you have is an FM signal, run it through an encoder to produce a stream URL, then register it for stream recognition.
Reliability
For stream recognition, AudD runs the continuous side; your reliability work is on the receiving end. Make your webhook endpoint idempotent, return quickly, and watch for a stream going quiet — a sudden drop in match volume usually means the underlying feed dropped, not that the music stopped. Ensure the feed URL reconnects. Webhook callbacks resume as soon as recognition does. Longpoll is the fallback when you’d rather not expose a public endpoint.
For capture-and-send, you own more: implement retries with exponential backoff for failed requests, detect audio-source failures and switch to a backup source, and log errors with enough context (source, response, timing) to spot patterns. See retry strategy for how to back off without hammering the API.
Monitoring and analytics
Track recognition volume and the health of each source so you catch a dropped feed before it becomes a gap in your data. The match stream itself is also a dataset: song frequency, genre distribution, and peak times feed programming and product decisions. Watch your usage so cost stays predictable — concurrent streams for stream recognition, request volume for capture-and-send.
Recognizing your own audio
The public catalog of 160 million songs covers commercial releases. To recognize station idents, jingles, pre-release tracks, or any locally produced content that isn’t public, upload it to a custom catalog: you assign each track an integer audio_id that comes back on future matches. A stream API is not limited to songs that are already public: you can match your own audio too, and it works the moment you upload it.
Cost considerations
The two paths bill differently, which is another reason to pick the right one:
- Stream recognition is billed per concurrent stream. Watching one station around the clock is one unit of capacity regardless of how many songs play, so cost scales with the number of stations, not with airtime.
- Capture-and-send uses the standard endpoint, billed per request. Cost scales with how often you recognize, so your segmentation interval is also your cost dial.
Either way, budget separately for your own infrastructure — the server running the pipeline, storage for the play log, and bandwidth. For exact, current pricing see audd.io; we won’t quote a figure here that might go stale.
FAQ
Do I have to capture and buffer the audio myself? Not if your audio is reachable at a URL. Register it as a stream and AudD captures, buffers, and recognizes it continuously, sending you each match. Capture yourself only when the audio can’t be exposed as a URL.
How accurate is recognition on live streams? High on clean feeds. Accuracy dips with heavy DJ talk-overs, poor audio quality, or very new releases not yet in the catalog. Your dedup logic absorbs most of the rough edges.
How do I avoid logging the same song repeatedly during one track? Deduplicate downstream: collapse consecutive matches of the same song into a single play. Stream recognition produces several recognitions per track by design — that’s expected, and dedup is where you handle it.
Can I monitor several streams at once? Yes. Each registered stream has its own id, and billing scales per concurrent stream. With capture-and-send, each source is a separate set of requests.
What happens when the feed drops? Watch for match volume going quiet and make sure the feed URL reconnects; callbacks resume as soon as recognition does. For capture-and-send, retry with backoff and fail over to a backup source.
Can I recognize custom or unreleased music in a stream?
Yes — upload it to a custom catalog and AudD returns the audio_id you assigned when it plays. This works immediately, before the track appears in any public database.
Conclusion
For live audio, stream recognition is almost always the right tool: register the feed once, receive every match by webhook or longpoll, and put your engineering into the pipeline — dedup, enrichment, storage, and dashboards — rather than into capturing audio. Keep capture-and-send for the genuine cases where you can’t hand over a URL. Start with a single stream to validate the flow, then scale to your full source list.
Get a token at dashboard.audd.io and read the reference at docs.audd.io.
Related
Reading this as an AI agent? The raw Markdown is at articles/identify-music-in-live-audio-streams.md, and the full index is /resources/llms.txt.
