elevenlabs.providers.sgit.ai / experiments / Captions studio — from character timings to SRT
Captions studio — from character timings to SRT
This API returns the start and end time of every character. Everything below is arithmetic on that array — and the arithmetic is ours, not the vendor's, which means it is ours to get wrong.
Your own full key, in your own browser, bounded only by your plan's monthly quota. That is pattern 0 with a ceiling: the narrow case where it is defensible — the key's owner, testing their own key, on their own device — and not a pattern to publish. No key ships in this page: the field below is empty until you fill it.
ElevenLabs offers no per-key spend limit for text to speech, so nothing here caps what a leaked key could cost you except the account's own quota. Use a key scoped in the dashboard to the endpoints this lab needs, and forget it when you are done. The version of this page with no key box at all is pattern three, and it does not exist yet.
This lab runs without a key. Paste an alignment object or a words.json array into section 1 and everything else works: the cue rule, the tables, the downloads. Only the karaoke preview needs audio, and only a live generation needs a key.
1 · Where the timing comes from
Paste an alignment object or a words.json array — this lab works with no key at all
2 · The cue rule — ours, not the vendor's
3 · Cues
| # | in | out | dur | chars | text |
|---|
4 · Karaoke — the reason to want per-word timing at all
Every word here is positioned by the API's own character timings, not by guessing at speech rate. In the pipeline this came from, the caption band already shows the narration text — this is what it would cost to highlight the word being spoken: nothing, because the timing arrives with the audio.
5 · Log
The technique, written down
Three steps, none of them provided by the vendor.
1 · Characters to words. A word is a maximal run of non-whitespace characters; its start is the first character's start and its end is the last character's end. Punctuation stays attached to its word, which is what a caption wants. Fifteen lines of JavaScript, in lab.js where you can read it.
2 · Words to cues. Start a new cue when the running text would exceed 84 characters (two lines of 42), when the gap to the next word is more than 0.6 s, or when the cue would run longer than 6 s. The three sliders above are those three numbers, and moving them re-cuts the whole subtitle file live.
3 · Wrap. Break each cue at the last space before 42 characters.
Those constants are a starting point that has never been checked against a human reading a finished video written, not run. If you tune them on real material, the numbers you land on are worth more than the ones here — send them back.
Why bother, when the platform auto-captions
Because auto-captions do not have the text. YouTube renders "2,788 nodes" as "two thousand seven hundred eighty eight nodes" and gets product names wrong every time. We have the ground-truth text and, now, the ground-truth timing — so uploading our own sidecar is strictly better and costs nothing beyond the generation we were paying for anyway.
The same timing array gives three more things the pipeline never had: chapter marks accurate to the sentence rather than to the scene; a caption band that can highlight the word being spoken; and a drift check with a cause — compare the alignment's last end time against the recorder's own duration and you learn whether drift is in the audio or in the recording.
What is verified here, and what is not
That the endpoint returns an alignment, and that it round-trips from a browser: verified, three samples, 5 September 2026 verified 5 Sep 2026. That the cue rule produces readable subtitles: unverified written, not run. That the alignment is accurate enough to highlight words in real time without visible lag: unverified — the karaoke preview above is where you would find out.