audd is AudD’s command-line tool. It identifies music in files, URLs, folders, and long recordings, monitors radio streams, and manages an AudD account. When its output is piped, as it is for an agent running shell commands, every command prints JSON, takes explicit spending limits, and exits with a documented code. This page covers what an agent needs to drive it: commands, output shapes, limits, errors, and the local MCP server. The full reference is at docs.audd.io/cli.
When to use the CLI, the API, or the MCP server
Use the CLI when you have a shell and a one-off or scripted job: identify a file, tag a folder, list the tracks in a mix, check a stream, or look up the account’s usage. When the code you are writing recognizes audio as part of an application, call the HTTP API or an official SDK from that code instead. The hosted MCP server at mcp.audd.io suits agents without a shell that need account tools (usage, the API token, plans, docs). audd mcp is a local MCP server that gives an agent recognition, enterprise scans, and streams through the CLI on its own machine.
Install audd
The install script puts audd in ~/.local/bin without sudo and checks the download against the release’s SHA-256 checksums. Every package contains the same single binary for macOS, Linux, and Windows on x86-64 and ARM64. --at clips need ffmpeg, and audd listen needs ffmpeg or sox; nothing else needs extra tools. The Docker image has no ffmpeg.
Run audd without installing it
Pick one way to run it and use it for every command in the session. The examples below write audd; put npx @audd/cli or uvx audd-cli in its place.
audd version prints one JSON document with version, commit, date, go, os, and arch.
Authenticate
Recognition needs an API token. Get your token at dashboard.audd.io. The simplest setup for an agent is a token the user puts in the environment:
audd reads the token from, in order: --token, AUDD_API_TOKEN, the token stored with audd config set token, and the token that audd login fetched. To store a token without it appearing in shell history or the process list, pipe it in:
Never print the token. audd token show masks it; leave off --reveal.
Sign in without a browser
If the user wants you to sign them in, run audd login. Without a terminal it uses the code method and prints a login_pending record as the first JSON line on stdout, then waits:
Show the user verification_uri_complete and user_code. They open the page on any device, check that it shows the same code, and approve. Keep the command running: it exits when the sign-in is approved, denied, or expires (the code lasts 15 minutes). On approval it prints a result line:
With an explicit --format json or --format csv, the login_pending record goes to stderr instead, so stdout keeps a single document. On the approval page the user can untick permissions; audd auth status shows what was approved. --browser and --device pick the method. With --browser and no terminal, the record has "method":"browser", a url to open, and a complete_with command to run if the browser is on another machine.
Check the sign-in and the token in use
audd auth status (also audd whoami) shows the profile, whether it is signed in, the approved permissions, and where the token comes from:
token_source is flag, env, config, login, or none. With no token at all, the command prints the document with "token_source":"none" and exits 3 with no_token.
Which commands need sign-in
Recognition (recognize, listen, catalog add), streams, api, and token show need only a token. account, usage, billing, token rotate, and token refresh-local need audd login; without it they exit 3 with login_required.
Profiles
Each profile has its own sign-in, token, and settings. Pass --profile work, set AUDD_PROFILE, or make one the default with audd auth switch work.
Read the JSON output
When stdout is not a terminal, output is JSON without any flag. Every document and every line has "schema_version": 1. Results go to stdout; notes, plans, and errors go to stderr.
One file or URL
result holds the song: artist, title, album, release_date, label, timecode (where in the song the clip matched), song_link, and, on plans that include them, isrc and upc. cached is true when the result came from the local cache (this URL had been recognized earlier); a fresh request prints false. A file with no match prints "result": null and exits 0:
A clip taken with --at adds a clip object with start_seconds and length_seconds. An enterprise scan has "enterprise": true and a matches array instead of result (see Find every song in a long recording). Fields that AudD adds later are passed through as they arrive.
Batches print JSON lines
A folder, glob, several files, or a list on stdin prints one JSON object per line. Each line has a type:
- event: job_started (with job_id, total, to_run) or job_resumed (adds done) comes first; dry_run is a plan printed with --format jsonl.
- result: one per file, with job_id, index, input, status (matched, no_match, failed, or pending), cached, result, and an error object for a failed file.
- summary: the last line, with counts for the whole job.
Streaming commands (streams watch, streams export, now-playing when piped, and streams history --format jsonl) print result and event lines in the same way.
A batch of three files, one matched, one with no match, and one failed:
That batch then printed a partial_failure error on stderr and exited 7. The summary’s counts, requests_spent included, cover the whole job, as audd jobs list reports them; requests_spent_this_run is what this run used. The summary status is done, partial (every file ran, some failed), stopped (a limit or an account error stopped it), or interrupted.
Trim the output with --fields, --format, and --quiet
--fields keeps only the fields you name, dotted for nested ones:
A field the output can never have is a usage error (exit 2) that lists the available fields, before anything is sent. A field one result lacks prints as null. In JSON lines, --fields trims result lines only, so event and summary lines keep their job ID and counts. It does not reach inside lists: select matches or tracks as a whole and filter them with jq.
--format table|json|jsonl|csv (or AUDD_FORMAT) picks the format. --quiet hides notes and progress on stderr; in table output it also prints only the song line (Tears For Fears — Everybody Wants To Rule The World). JSON output does not change with --quiet.
CSV columns
CSV has the same flat columns for one file and for a batch:
job_id is empty for a single input. An enterprise scan prints one row per match, with start_seconds and end_seconds filled in.
Errors on stderr
A failed command prints one JSON document on stderr:
code is a stable string, listed in Error codes and what to do. api_code is AudD’s own error number when the API returned one, else 0. hint is usually the exact command that fixes the problem. "retryable": true means waiting and trying again can help; false means it will not.
Spending limits and confirmations
Anything that can spend many requests needs an explicit bound. When the bound is missing, the command exits 6 before sending anything:
- A folder, glob, several files, or a list on stdin is a batch and needs --max-files N.
- --enterprise is billed per 12 seconds of audio and needs --limit N (12-second chunks per file).
- Without a terminal, a run that can spend more than one request needs --yes. A single standard recognition never asks.
- --max-requests N stops a run before it spends more than N requests. audd config set max_requests N sets a default.
--dry-run works without --max-files or --limit and sends nothing. Run it first, show the user the plan, and add --yes only after they agree. Never pass --limit none or --max-files none unless the user asked for everything.
A folder without --max-files:
More files than --max-files allows:
A bounded run without --yes prints the plan on stderr, then the error:
A run stopped by --max-requests can be resumed:
Read the dry-run plan
input names the file or URL for a single input and is null for a batch. job_id is set when the run would resume an unfinished job. cost_usd uses the pay-as-you-go price of $5 per 1,000 requests. Cached files cost nothing and are counted in cached_files. For an enterprise scan of a URL, whose length is unknown, the plan without --limit has no ceiling:
With --limit 20, the same plan has "requests":20, "approximate":true, and "cost_usd":0.1. With --format jsonl, the plan is one line with "type":"event" and "event":"dry_run", so it is never counted as a file’s result.
Exit codes
A batch where some files had no match still exits 0. Add --fail-on-no-match to exit 1 instead; failed files take precedence (exit 7).
Error codes and what to do
Inside a batch, a file’s error.code uses the same names. A file whose request was being sent when audd stopped is recorded as interrupted_in_flight: AudD may have counted it, so it is sent again only with --retry-failed.
Common tasks
How to identify a song from a file or URL
The standard endpoint analyzes up to the first 12 seconds of audio and takes files up to 10 MB. Audio and video files both work. Results are cached by file contents (URLs for 24 hours), so recognizing the same audio again is free; --no-cache sends it anyway, and audd cache clear empties the cache. audd listen records from the microphone (10 seconds by default, up to 60 with --seconds) and identifies what is playing.
Get Apple Music, Spotify, Deezer, or MusicBrainz metadata
--return takes apple_music, spotify, deezer, and musicbrainz. Each adds a block under result with that service’s IDs and links. It does not work with --enterprise.
Identify a song later in a file
--at sends a 12-second clip (or the length in --duration) starting at that time. It accepts 90, 1:30, or 1m30s and needs ffmpeg. The output adds a clip object; for --at 0:30 it is "clip":{"start_seconds":30,"length_seconds":12}.
Scan a folder safely
- Preview the plan. Nothing is sent: audd recognize ./recordings --max-files 200 --dry-run
Preview the plan. Nothing is sent:
- Show the user plan.files, plan.requests, and plan.cost_usd, and ask whether to go ahead.
Show the user plan.files, plan.requests, and plan.cost_usd, and ask whether to go ahead.
- Run it with --yes, writing JSON lines or CSV to a file: audd recognize ./recordings --max-files 200 --yes > results.jsonl audd recognize ./recordings --max-files 200 --yes --format csv > results.csv
Run it with --yes, writing JSON lines or CSV to a file:
A glob or a list on stdin works the same way. A list on stdin needs --yes whenever it would spend requests, because the list takes up stdin and audd cannot ask:
--concurrency N sets the number of parallel requests (default 4). Add --max-requests N to cap the run.
Resume an interrupted batch
Every batch is a job saved after each file, so a stopped run loses no finished files. Do not start it again from scratch:
audd jobs list prints {"schema_version":1,"items":[...]}, one item per job with id, inputs, total, done, no_match, failed, pending, remaining, requests_spent, and status. audd jobs resume sends only the files that are left. Files that failed after their upload started, or that were being sent when audd stopped, may have been counted, so they are sent again only with --retry-failed.
Running the same batch command again while its job is unfinished exits 6:
Pass --resume to continue that job or --new to recognize every file again. A resumed run prints results only for the files that were left; audd jobs show <id> lists them all. audd jobs clean deletes old jobs (--older-than 30d by default, --all for every job that is not running).
Find every song in a long recording
The enterprise endpoint scans a whole file and returns every match with its position. It is billed per 12-second chunk, so it needs --limit:
Each item in matches has the song fields plus score, start_offset and end_offset (milliseconds within the chunk), and start_seconds and end_seconds (from the start of the file). --tracklist adds a tracks array that merges consecutive matches of the same song. Trimmed with --fields tracks:
--skip, --every, --skip-first-seconds, --use-timecode, and --accurate-offsets are passed to the enterprise endpoint. For a local file, the plan uses its length (exact with ffprobe installed, otherwise estimated from the file size). A URL’s length is unknown, so --limit is the only ceiling. See enterprise cost control for choosing a limit.
Monitor radio streams
Stream monitoring has to be enabled on the account. Add a stream under an ID you choose, then read its results:
streams add prints {"schema_version":1,"added":true,"radio_id":1,...}. With --start, AudD sends each result when a song starts instead of when it ends. streams remove <id> needs --yes without a terminal.
audd now-playing --once prints the latest song on each stream:
state is just_played and later last_recognized for results sent when a song ends (the default, with played_seconds and ended_at), or playing for streams added with --start (with elapsed_seconds). length_seconds appears only when stream results carry Apple Music, Spotify, or Deezer metadata, which audd streams callback set <url> --return apple_music turns on. A stream whose results cannot be read is listed with an error object; the command exits 5 only when no stream can be read.
audd streams watch prints a result line per play and event lines for stream health:
streams history prints {"schema_version":1,"since":...,"plays":[...],"gaps":[...]}, newest first. gaps are periods when a stream was not recorded, so totals may miss plays there. streams report prints rows of key, plays, airtime_seconds, and stations, with "complete": false when gaps mean the totals miss plays. --by takes song, artist, label, or station.
The first streams command starts a background recorder that receives every result over longpoll and saves it to a local database, so history and reports stay complete. audd streams recorder status|start|stop manages it, audd streams record runs it in the foreground, and audd config set streams.background_recorder false turns it off.
Live results need a callback URL on the account. When none is set, streams watch stops with callback_url_required (exit 6) unless you pass --yes, which sets the placeholder https://audd.tech/empty/. To use your own receiver, run audd streams callback set <url>. --forward-to URL on streams watch and streams record also POSTs each result to a URL, shaped like an AudD callback, for testing a handler locally. More in the streams agent notes.
Check usage and manage the account
These need audd login:
audd usage prints allowance, used_this_cycle, remaining, cycle_start, cycle_end, and a daily array of date and requests. --check --min-remaining N exits 8 when fewer than N requests remain.
Billing commands never charge anything. They print a Stripe link for the user to open and approve:
Give payment_url to the user; do not open it for them. audd token rotate disables the current token everywhere at once, so run it only when the user asks; without a terminal it needs --yes. audd token refresh-local fetches the current token from the account again. audd token show needs only a token and prints it masked.
Add a song to a custom catalog
This fingerprints the song into the account’s custom catalog under audio_id 42, replacing any song already under that ID. It does not recognize anything. Custom catalog access is enabled per account; without it the command exits 4 with not_enabled. Each upload is billed and is never retried automatically, even after a server or network error, because the first upload may have been counted. Ask the user before you run it again. See the custom catalog agent notes.
Use audd as a local MCP server
audd mcp runs an MCP server over stdin and stdout. Each tool runs the matching audd command with this machine’s token, profile, results cache, and stream store.
Add it to Claude Code, Cursor, and other clients
For clients configured with JSON, such as Cursor and Claude Desktop, run the command audd with the argument mcp:
Leave out env when audd is signed in or has a stored token. Add --profile NAME to the arguments to use another profile.
Tools and parameters
Each tool takes one file. A folder path is refused with a hint to run audd recognize <dir> --max-files N instead. A tool that fails returns an error result whose text ends with the error code and exit code:
How limits apply to MCP tool calls
--max-requests N given to audd mcp is a ceiling for the whole session. A recognize or catalog_add call counts as one request, and an enterprise scan counts as its limit. When less is left than a scan’s limit, the limit sent is lowered to what is left; a call that would go over the ceiling is refused. Dry runs, cached results, and calls that fail with exit code 2, 3, 4, or 6 are not counted. A real recognize_enterprise call always needs a limit of 1 or more, so call it with dry_run set to true first to see the estimate.
Other commands for agents
- audd agent-setup writes instructions that teach a coding agent to use audd: a Claude Code skill (.claude/skills/audd/SKILL.md), a Cursor rule (.cursor/rules/audd.mdc), or an audd section in AGENTS.md. Without a flag it writes one for each agent it finds set up in the project, or AGENTS.md when it finds none. --claude, --cursor, --codex, and --agents-md pick targets, and --print prints the text instead of writing files. Running it again updates the files in place.
- audd docs <topic> prints AudD documentation as markdown: api, enterprise, streams, upload, mcp, sdks, or cli. The cli topic works offline. Without a topic it lists them.
- audd commands --json prints every command, flag, output shape, and exit code as JSON. Shortcuts such as audd logout name the command they run in alias_of.
- audd api <method> key=value... calls any API method and prints the response with "schema_version": 1 added. The token is added for you, and passing api_token= is an error. Each call is sent once and never retried, and recognition methods are billed as usual. The exit code follows the response’s status.
Troubleshooting
Why does audd return "result": null?
The audio did not match any song. This is not an error, and the exit code is 0. The standard endpoint analyzes only the first 12 seconds, so try another moment with --at 1:00, or scan the whole file with --enterprise --limit N. Pass --fail-on-no-match if a script should exit 1 instead.
Why does --at fail with missing_tool?
--at clips and audd listen need ffmpeg (audd listen can also use sox), and the Docker image does not include it. The error is missing_tool (exit 2). Install ffmpeg with a package manager, or recognize the file without --at.
What do quota_exceeded and rate_limited mean?
quota_exceeded (exit 4) means the account has no requests left this billing cycle; audd usage shows the numbers and audd billing plans lists plans. rate_limited means AudD is receiving too many requests from the token. A batch waits and retries on its own after HTTP 429 and stops on API error 611; resume it later with audd jobs resume.
Why does audd streams watch fail with callback_url_required?
Live stream results reach audd only when the account has a callback URL. Run audd streams callback set with your own URL, or pass --yes to set the placeholder https://audd.tech/empty/, which accepts and discards callbacks.
Why did --token test stop working?
The public test token allows 10 standard recognitions a day, shared by everyone who uses it, and does not cover enterprise scans or streams. When the limit for the day is used up, audd exits 3 with token_rejected and API error 901. Get your own token at dashboard.audd.io.
How do I use audd behind a proxy?
audd honors the HTTPS_PROXY and NO_PROXY environment variables. A network error (exit 5) suggests checking HTTPS_PROXY when a proxy is in use.
How do I see what audd sends to AudD?
Add --debug to any command. It logs each HTTP request to stderr with tokens removed.
Why does rerunning a batch exit 6 with resume_available?
An earlier run of the same files with the same settings did not finish. Pass --resume to continue it, --new to recognize every file again, or run audd jobs resume with the job ID from the hint.
Why is requests null in a dry-run plan?
An enterprise scan of a URL without --limit has no ceiling, because the length of a URL is unknown. The plan shows "unbounded": true. Add --limit N to cap each file at N 12-second chunks.
- Identify music from the command line
- Standard, enterprise, or streams: how to choose
- Agent notes: the enterprise endpoint
- Agent notes: streams and longpoll
- CLI reference on docs.audd.io

