---
title: "Migrate from ACRCloud to AudD"
description: "Map ACRCloud's signed-request identification model to AudD's token-authenticated HTTP API, with before/after auth and recognition snippets."
slug: "/resources/migrate/from-acrcloud"
section: "migrate"
keywords: [audd, acrcloud, migration, music recognition api, audio fingerprinting]
---

# Migrate from ACRCloud to AudD

This page is for engineers running on ACRCloud who are evaluating AudD as the
recognition backend. Both are cloud audio-fingerprinting services: you send
audio, you get back the recognized track. The two main things that change in
your code are **how you authenticate** (ACRCloud signs each request with an
HMAC over an access key/secret; AudD takes a single `api_token` form field)
and **which endpoint handles which job** (short clip, long file, or live
stream). This guide maps the concepts and shows the equivalent AudD calls.

## Concept mapping

| ACRCloud concept | AudD equivalent |
|---|---|
| `host` (region endpoint) | One global host: `https://api.audd.io/` (standard) and `https://enterprise.audd.io/` (long audio). No per-region host to select. |
| `access_key` + `access_secret` + HMAC `signature` | A single `api_token` form field on every request. No request signing. |
| Identify (recognize) endpoint | `POST https://api.audd.io/` — the standard endpoint, for a short audio clip. |
| File Scanning / bucket scanning | `POST https://enterprise.audd.io/` — chunks a long file server-side and returns every match. |
| Broadcast / channel monitoring | AudD **streams** endpoints on `api.audd.io` (`addStream`, `setCallbackUrl`, plus `GET /longpoll/`). |
| Custom bucket of your own audio | AudD **custom catalog** (`POST api.audd.io/upload/`). |
| Metadata (ISRC, UPC, external IDs) | Result fields `isrc`, `upc`, plus optional `apple_music` / `spotify` / `deezer` / `musicbrainz` blocks via `return`. |
| Official SDKs | 11 official AudD SDKs (Python, Node, Go, Rust, PHP, Swift, Kotlin, .NET, Java, C, C++). |

## The equivalent call

### Authentication

The biggest code change is auth. ACRCloud requires you to build a signing
string and compute an HMAC-SHA1 over your access secret for each request:

```python
# Before — ACRCloud: build an HMAC signature per request
import base64, hashlib, hmac, time, requests

access_key = "your-access-key"
access_secret = b"your-access-secret"
host = "identify-eu-west-1.acrcloud.com"

http_method = "POST"
http_uri = "/v1/identify"
data_type = "audio"
signature_version = "1"
timestamp = str(time.time())

string_to_sign = "\n".join(
    [http_method, http_uri, access_key, data_type, signature_version, timestamp]
)
signature = base64.b64encode(
    hmac.new(access_secret, string_to_sign.encode(), hashlib.sha1).digest()
).decode()

with open("clip.mp3", "rb") as f:
    sample = f.read()

resp = requests.post(
    f"https://{host}{http_uri}",
    files={"sample": sample},
    data={
        "access_key": access_key,
        "data_type": data_type,
        "signature_version": signature_version,
        "signature": signature,
        "sample_bytes": len(sample),
        "timestamp": timestamp,
    },
)
print(resp.json())
```

AudD authenticates with one form field — `api_token` — and the official SDK
sets it for you from the constructor or the `AUDD_API_TOKEN` environment
variable. There is no signing string, no timestamp, no HMAC:

```python
# After — AudD: a single api_token, set once
from audd import AudD

audd = AudD("your-api-token")  # or reads AUDD_API_TOKEN from the environment

song = audd.recognize("clip.mp3")
if song:
    print(f"{song.artist} — {song.title}")
else:
    print("no match")  # result: null is a successful no-match, not an error
```

If you call the HTTP endpoint directly instead of through an SDK, the whole
request is a multipart POST with `api_token` and the audio:

```bash
# After — AudD over raw HTTP
curl https://api.audd.io/ \
  -F api_token=your-api-token \
  -F file=@clip.mp3 \
  -F return=apple_music,spotify
```

> **`api_token` is a bearer-style secret — keep it server-side.** Because
> there is no per-request signature, anyone holding the token can spend your
> quota. Hold it on your backend (or in a secret manager), never in client
> code. Rotate it from [dashboard.audd.io](https://dashboard.audd.io).

### Recognizing a short clip

ACRCloud's identify endpoint and AudD's standard endpoint both take a short
sample and return the top match. AudD's standard endpoint responds in under 2
seconds, caps the upload at 10 MB, and matches against a database of 160
million songs. Accepted audio formats: MP3, WAV, FLAC, M4A, OGG, AAC, WMA,
AIFF.

```python
song = audd.recognize(
    "https://audd.tech/example.mp3",
    return_metadata=["apple_music", "spotify"],
)
if song:
    print(song.artist, "—", song.title)
    print("Apple Music:", song.streaming_url("apple_music"))
    print("Universal link:", song.song_link)
```

A successful call that matched nothing returns `None` (the API sends
`result: null`). That is distinct from an error — treat it as "try again,"
not as a failure.

### Scanning a long file

Where you used ACRCloud's file-scanning to walk a long recording, use AudD's
**enterprise** endpoint. It chunks the file server-side and returns every
match in order.

```python
matches = audd.recognize_enterprise(
    "https://audd.tech/example.mp3",
    limit=10,  # stop after 10 matches; ALWAYS set this in development
)
for m in matches:
    print(m.timecode, m.artist, "—", m.title, m.isrc)
```

> **Always set `limit` on enterprise calls during development.** The
> enterprise endpoint bills per 12 seconds of audio processed. An unbounded
> call on a multi-hour file ingests the whole thing. `limit=N` stops after N
> matches.

### Monitoring a broadcast or live stream

Where you used ACRCloud's broadcast monitoring, use AudD's **streams**
endpoints. You register a callback URL and add a stream; AudD recognizes
songs as they play and POSTs each match to your callback.

```python
audd.streams.set_callback_url("https://your-server.example/audd-callback")
audd.streams.add(url="twitch:somechannel", radio_id=1)
```

`radio_id` is an integer you choose — not a name. Unlike ACRCloud's
string stream keys, it's a number you assign to each stream and that comes
back on every callback so you can tell streams apart.

The stream URL accepts direct stream URLs (HLS, Icecast, m3u/m3u8) and the
shortcuts `twitch:<channel>`, `youtube:<video_id>`, and
`youtube-ch:<channel_id>`. If you cannot host a public callback URL, poll
`GET /longpoll/` instead (`audd.streams.longpoll(...)`).

## What's different

- **Authentication model.** ACRCloud signs each request with an access
  key/secret and an HMAC signature (plus a timestamp). AudD uses a single
  `api_token` form field with no request signing. Less code on your side;
  also means the token must be protected like any bearer secret.
- **Endpoint selection.** ACRCloud separates products by use case (identify,
  file scanning, broadcast monitoring) and by region host. AudD uses one
  standard host for clips, one enterprise host for long audio, and the
  streams endpoints for live monitoring — with no region host to choose.
- **No-match signal.** AudD returns `status: "success"` with `result: null`
  on a clean no-match, distinct from an `error` response. Branch on that
  explicitly so a quiet clip isn't treated as a failure.
- **Enterprise billing unit.** AudD's enterprise endpoint bills per 12
  seconds of audio processed and expects a `limit`. Budget around audio
  duration, not just request count.
- **Custom audio.** ACRCloud lets you scan against your own buckets; AudD
  lets you upload your own tracks to a custom catalog
  (`POST api.audd.io/upload/`, access gated — email api@audd.io). A
  custom-catalog match returns `audio_id`, and `artist`/`title` may be null
  if you didn't supply them at upload time.
- **Metadata fields.** AudD returns `artist`, `title`, `album`,
  `release_date`, `label`, `timecode`, `song_link`, and (on enterprise calls
  or Startup-plan-and-above accounts) `isrc` and `upc`. Provider blocks
  (`apple_music`, `spotify`, `deezer`, `musicbrainz`) are returned
  only when you request them via `return`.
- **Pricing visibility.** AudD's per-request pricing is public: 300 free
  requests on signup with no card, then $5 per 1,000 requests pay-as-you-go,
  with volume plans listed on the dashboard.
- **SDK coverage.** AudD ships 11 official SDKs, so the same auth and
  recognition contract is available across languages without hand-rolling a
  client.

## Migration steps

1. **Get an AudD token.** Sign up at
   [dashboard.audd.io](https://dashboard.audd.io) (300 free requests, no
   card) and copy the `api_token`.
2. **Install the SDK for your language.** For example, `pip install audd`,
   `npm install @audd/sdk`, or `go get github.com/AudDMusic/audd-go`. See the
   [SDK docs](https://docs.audd.io/sdks) for all 11.
3. **Replace the signing code with the token.** Delete the HMAC/signature
   builder and the `access_key`/`access_secret`/`timestamp` form fields.
   Construct the client with `api_token` (or set `AUDD_API_TOKEN`).
4. **Map each call site to an endpoint.** Identify → standard
   `recognize(...)`. File scanning → `recognize_enterprise(..., limit=N)`.
   Broadcast monitoring → streams (`set_callback_url` + `add`), or
   `longpoll` if you can't host a callback.
5. **Re-map the response fields.** Point your code at AudD's result schema
   (`artist`, `title`, `album`, `release_date`, `label`, `timecode`,
   `isrc`, `upc`, `song_link`, and provider blocks). Add an explicit
   `result == null` branch for no-match.
6. **Move custom audio, if any.** If you relied on ACRCloud buckets of your
   own tracks, request custom-catalog access (email api@audd.io) and upload
   via `POST api.audd.io/upload/`.
7. **Verify with a fixed file.** Run a known input
   (`https://audd.tech/example.mp3`) through each migrated path and confirm
   the fields you depend on are present before switching production traffic.

---

**Related**

- [Standard, enterprise, or streams: how to choose](/resources/concepts/standard-vs-enterprise-vs-streams)
- [Public database vs your custom catalog](/resources/concepts/custom-vs-public-db)
- [SDK docs](https://docs.audd.io/sdks)
- [API reference](https://docs.audd.io)