---
title: "How to handle audio recognition at scale: architecture and best practices"
description: "Architectural patterns for running audio recognition at scale — queue-based processing, caching, rate-limit handling, resilience, and cost control with AudD."
slug: "/resources/articles/audio-recognition-at-scale-architecture-best-practices"
section: "articles"
keywords: [audd, audio recognition, scale, architecture, queue processing, rate limiting, recognition api]
---

# How to handle audio recognition at scale: architecture and best practices

A recognition system that works for a few hundred requests a day often breaks
when it has to process millions. The gap between a proof of concept and a
production system is less about raw throughput than about reliability, latency,
cost control, and graceful failure handling.

This guide covers the architectural decisions that matter when building
audio recognition into a system that needs to scale, and how AudD's API and SDKs
fit those patterns.

## Define what "scale" means for you

Before choosing an architecture, characterize the workload — the answers point at
different designs.

**Volume pattern matters more than peak.** A distributor processing catalog
uploads sees predictable batches. A user-generated-content platform faces random
spikes. A radio-monitoring service handles steady, continuous streams. For the
last case, reach for AudD's **streams** mode — you register a source once and
receive matches as songs play, instead of polling — rather than treating live
audio as a flood of one-off requests.

**Latency requirements shape everything.** Real-time features need sub-second
responses; batch jobs tolerate minutes. Content moderation sits in between — fast
enough to catch violations, slow enough to batch intelligently.

**Accuracy-vs-speed tradeoffs become real.** At scale, a small accuracy gain can
justify added latency, but a change that doubles processing time rarely does.

## Core architecture patterns

### Queue-based processing

Direct, synchronous calls work until they don't. Once you're processing thousands
of files, a queue gives you reliability and observability.

```
Audio input → message queue → worker pool → results storage
```

A queue decouples ingestion from recognition, so upstream systems don't time out
while a job runs, and you get natural backpressure when workers fall behind.
Redis, RabbitMQ, or a cloud queue like SQS all work — the requirement is that
messages survive a worker crash.

### Worker pool management

- **Scale horizontally.** Recognition parallelizes across files, not within a
  single call, so many small workers beat one large machine.
- **Set timeouts and health checks.** A worker that hangs on a bad file will
  eventually exhaust the pool; time out stuck work and restart unhealthy workers.
- **Watch memory.** Decoding audio consumes RAM; size pools to avoid swapping or
  OOM kills.

### Caching

Fingerprinting is deterministic — the same audio yields the same result — which
makes caching effective.

- **Hash the audio, not the filename.** Two files with different names but
  identical audio should hit the cache; key on a content hash (e.g. SHA-256 of
  the bytes).
- **Cache at multiple levels.** Avoid re-recognizing identical inputs, and avoid
  redundant downstream lookups.
- **Mind freshness.** The catalog grows, so a track that didn't match last month
  might match today. Balance cache lifetime against result freshness for inputs
  that previously returned no match.

## Rate limiting and request shaping

Design the client to respect limits while maximizing useful throughput.

- **Back off exponentially** on rate-limit responses instead of retrying
  immediately, to avoid a thundering herd.
- **Spread work across time.** If you have far more files than your hourly
  allowance, schedule the work over hours rather than bursting.
- **Avoid duplicate processing.** Check the content hash before sending — the
  cheapest request is the one you don't make.

For long inputs, the standard endpoint returns one top match per call, which
suits short clips. To identify *every* song in a long file, use the
**enterprise** endpoint, which chunks the audio server-side and returns each
match with timestamps, billed per 12 seconds — far more efficient than slicing
the file yourself and firing many standard calls.

```python
matches = audd.recognize_enterprise("long-broadcast.mp3", limit=20)
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.

## Error handling and resilience

### Classify failures

Not all errors deserve the same response. The SDKs raise typed exceptions you can
branch on.

- **Transient failures** (network timeouts, brief unavailability) — retry with
  backoff. The SDK already retries connection-level failures *before* your bytes
  reach the server, and deliberately does not re-send a recognition call after
  the upload completed, to avoid double-billing.
- **Caller errors** (bad token, undecodable audio, exhausted quota) — don't
  retry blindly; log them and route to a dead-letter queue or fix the input.
- **No match** — `recognize` returns `None`/`null`. This is a normal outcome, not
  an error; record it and move on.

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

try:
    song = audd.recognize("clip.mp3")
except AudDAuthenticationError:
    ...  # config problem — bad/missing token
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; inspect e.error_code / e.server_message
```

### Circuit breakers and dead-letter queues

Wrap the external call in a circuit breaker: track error rates over a sliding
window, open when they cross a threshold, allow a trickle through in half-open
state, and close when success recovers. This stops workers from burning time on
calls that will fail and gives the service room to recover.

Route inputs that can never succeed to a dead-letter queue with enough context to
debug — original metadata, the error, retry count, timestamps — so they don't
block the main flow.

## Performance optimization

**Preprocess audio.** A short clip is enough for the standard endpoint and keeps
you under its ~10 MB cap; trimming long source files to a representative segment
cuts bandwidth and latency. AudD decodes common formats server-side, so you
generally don't need to transcode.

**Reuse connections.** Pool HTTP connections rather than opening one per call —
the per-connection overhead adds up at scale.

**Measure everything.** Track requests per second, response times, error rates by
class, queue depth, and cost per recognition. Alert on the leading indicators —
queue depth growing faster than drain rate, error rates above baseline, latency
degrading.

## Cost control

- **Deduplicate aggressively.** Content-hash checks prevent paying twice for the
  same audio.
- **Sample long content strategically** when you only need a sense of what's in
  it, and reserve the enterprise endpoint for when you genuinely need every
  match.
- **Auto-scale on queue depth.** Grow worker pools when the queue grows and shrink
  them when it drains, so capacity tracks demand.

For current pricing, see [dashboard.audd.io](https://dashboard.audd.io); knowing
the per-request and per-stream cost lets you model caching and batching savings
precisely.

## Deployment

Recognition systems often run continuously, so favor zero-downtime rollouts.
Blue-green deployments let you validate a new version on a parallel environment
before switching traffic, and gradual rollouts let you push recognition or
integration changes to a small slice of traffic, watch error rates, and roll back
fast if something regresses. For schema changes, add columns before deploying code
that reads them and migrate data in off-peak batches.

## Wrapping up

Recognition at scale is an exercise in handling the unhappy path: queue work,
cache deterministically, classify failures, break circuits, and measure
everything. The patterns here apply regardless of provider, but an API with
predictable behavior and clear pricing makes them easier to implement. AudD
matches against 160 million songs, returns typed errors the patterns above
key on, and offers standard, enterprise, and streams modes so you can match the
architecture to the workload.

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

---

**Related**

- [Standard, enterprise, or streams: how to choose](/resources/concepts/standard-vs-enterprise-vs-streams)
- [Retry strategy](/resources/concepts/retry-strategy)
- [Enterprise cost control](/resources/concepts/enterprise-cost-control)
- [API reference](https://docs.audd.io)