Skip to main content
Send Cue a track and get back every beat, and separately every downbeat: the first beat of each bar, the one you’d count to. Beats tell you where the pulse is. Downbeats tell you where a cut can land without sounding wrong. That second grid is the hard one, and it’s the one the rest of Cue depends on. Every sync point we return is a bar line, so a grid off by a single beat produces edits that pass every automated check and sound wrong to everyone.

Map a track

Only audio_url is required. known_bpm is the one optional field worth knowing about. It is worth +6.7 downbeat CMLt, but only if the number is right, meaning a measured or carefully entered catalog tempo. A guess buys nothing, and a value that disagrees with what we read is discarded. Leave it out for live recordings, for anything with a rubato or free-time section, and for a catalog you inherited and haven’t checked. More on when to send it.

Getting us the audio

Send a signed HTTPS URL from wherever your audio already lives. Nothing has to be public, and you do not need to be on any particular cloud. Every major store signs URLs: All we need is a link that is reachable from the public internet, returns the audio file itself rather than a web page, and responds within 120 seconds.
Sign for 12–24 hours when you are mapping a catalog, not the usual one hour. Jobs queue, so a link signed for an hour can expire while its job is still waiting. That surfaces as a fetch error that looks like a problem on your side and isn’t.
We fetch from the public internet with no fixed source address, so you cannot allow-list us by IP. The signature on the URL is the access control. s3:// URIs are also accepted, but only for buckets outside our own account and only once you have granted our worker read access with a bucket policy. Talk to us if you want that. A signed HTTPS URL needs no setup and is the path we recommend. Mapping a track is real work on real audio, and a ten-minute mix is a few minutes of it, so every call is a job:
202
The submit itself only checks that audio_url is present and is an https:// or s3:// URL. Everything about the audio is decided by the worker after it fetches the file, and reaches you on the poll: that it is audio, that it decodes, that it’s inside the length limit.

Poll for the grid

While it’s working you get a 202 carrying stage: queued means it hasn’t been picked up yet, running means a worker has it. A backlog is a normal state when you’re mapping a catalog, and those two are the difference between waiting your turn and a hang. When it’s done:
200
Times are seconds from the start of the audio. downbeats is a subset of beats, the ones that open a bar, so one response drives both a beat grid and a bar grid. track_id is yours, not ours. Whatever you send comes back on the job, so you can map a whole catalog without keeping your own job_id → track table. cached is true when you have mapped these exact bytes before. We keep the grid against a hash of the audio, per account, so a re-run skips the analysis. It does not change what the call costs. A job that fails answers 422 with the reason, and a failed job is never billed. So does a job that started but will not finish, and one that sat in the queue past its retention.

Retrying safely, and re-running a catalog

Set an Idempotency-Key header on POST /v1/beats and a retry after a network blip returns the original job instead of starting a second one, so a timeout you never saw the response to cannot bill you twice. That replay is marked with "idempotent_replay": true. Keys are honoured for 24 hours. Reusing one for a genuinely different request is a 422 rather than a silent alias.
Re-signing the URL between attempts is fine. We identify the request by the object it points at, not by the signature on it. If you already know the SHA-256 of the audio, send it as audio_sha256. When you have mapped that track before, we answer from the cache without fetching the file at all. That is what you want when you are re-running a catalog and would rather not serve it twice.
/v1/beats is the only endpoint where the key returns the original result. Everywhere else an Idempotency-Key only stops a duplicate billing row. See the reference.

If your catalog knows the tempo, send it

known_bpm is optional and it is the single largest decoder lever we have. Constraining the decoder to ±20% around a known tempo stops it hunting, and on GTZAN 993 that is worth +6.73 downbeat CMLt, moving 0.7507 to 0.8180. That is several times more than any change we have made to the model itself. It tolerates an imprecise value well, because what matters is that the true tempo stays inside the window we search: That last pair is why this is opt-in. A wrong octave, 64 for a 128 BPM track or 256, is far worse than sending nothing, because it puts the true tempo outside the window and forces an error the tracker would never have made alone. A catalog with only 10% of its rows octave-wrong nets −0.26: the entire benefit, erased. So we check before we trust it. We decode once without the hint, and if your number sits about an octave away from what we read, we discard it and map the track normally. You cannot make the result worse by sending a bad tempo. At worst you have paid for a hint we ignored. Percentage error is fine. Octave error is the one to care about, and if your catalog has any doubt about doubling, leave the field out. known_bpm accepts 20 to 400.

Songs that change tempo

A window around one number fits a song with one tempo, not one that speeds up. Measured on our training corpora, 9.9% of anime and game tracks and 15.9% of RWC have a tempo curve that will not fit inside a ±20% window at all. GTZAN is 1.1%, which is exactly why the standard benchmark cannot see this. So we read how much the tempo actually moves in a first pass and widen the window to cover it, never past an octave. A window spanning 2× would re-admit the half/double error the octave check exists to exclude. A track whose own curve is wider than an octave falls back to an unconstrained decode. Send the tempo you have. Nothing changes on your side.

Why the downbeat is the hard part

Beats are comparatively easy. A metronome finds most of them, and trackers have been good at them for years. Knowing which beat starts the bar is where they fail, and it’s the failure that matters commercially: a grid shifted by one beat looks correct in every metric that isn’t measuring bar position. CMLt is the measure that catches it: the longest stretch of the track you can trust before the grid drifts off the bar. It is the number to hold us to. On GTZAN 993, held out of our training: Scoring the same predictions with our own harness reproduces published figures to within 0.002, so those rows are on one scale. Two things to read carefully. That +2.1 comes from the fine-tune, not from anything clever in the decoder. And run-to-run variance from the random seed alone is about 1.0 CMLt on this benchmark, so treat any margin under roughly 1.5 as unresolved, including margins we quote. GTZAN is made of 30-second excerpts, which is what every published beat-tracking number is measured on, ours included. Longer tracks are split into 30-second chunks and stitched, using the reference implementation’s own chunk size and overlap handling, so a served grid is the same computation as a benchmarked one.

Global repertoire

The public research corpora this field standardises on are overwhelmingly Western, and a model trained only on them slips on Asian popular and game music. Dense percussive layers, frequent half-time and double-time feels, and tempi well above the Western pop band are all thin in the standard datasets, and bar-position errors concentrate exactly there. Cue is fine-tuned on 5,293 tracks: the sixteen public corpora plus roughly 740 tracks of East Asian popular and rhythm-game repertoire absent from them.
That is a statement about training data, not a measured accuracy claim. Our only reading on held-out material of that kind is 99 anime tracks, where Cue scored 0.7730 downbeat CMLt against 0.7694 for the generalist model. At n=99, and against ~1.0 CMLt of seed variance, that difference is inside the noise. We would rather score your catalog than estimate it.
If your catalog is Western pop, the GTZAN table above is the one that applies.

Very fast and very slow music

Beat trackers search a tempo range, and the default here is 55 to 215 BPM. Outside it the right answer is not on the menu, and a 240 BPM track comes back at 120. No model quality fixes that. We widen the search when the evidence says a track belongs outside, taken from your known_bpm or from the track’s own first pass. On GTZAN’s 34 tracks above 215 BPM, widening is worth +41.25 downbeat CMLt. It holds on stock Beat This, which we never trained, and on all five of our own checkpoints, which makes it a property of the decoder rather than of our weights. The floor moves the same way. A track whose evidence puts it under 55 BPM gets a lower floor rather than being forced to double tempo. Widening only where it’s needed is the point. Applied unconditionally it costs 0.29 to 0.83 CMLt on the 95% of tracks that never needed it, so ordinary songs keep the original window.

What it costs

$0.008 per minute of audio, rounded up, one-minute minimum. Billed once, when the job completes. A job that fails isn’t billed. Tracks longer than 30 minutes are refused, but not at submit time. The submit returns 202 like any other. The worker fetches the file, reads its duration and refuses it there, and you learn about it as a 422 on your next poll of GET /v1/beats/{job_id}. Nothing is billed for it. See Metering & pricing for the rest of the rate card, and Errors & limits for the failure shapes.