2026-10-28 · 6 min read
A Caption API for Twitch Clips: Turn VOD Highlights into Captioned Shorts
Twitch clips have a specific problem: they are loud, fast, full of overlapping voices and game audio, and they are often watched muted in a feed. A forty-second highlight with no captions asks a lot of a muted viewer. With word-timed captions, the same clip stays followable with the sound off.
If you build a clipping tool or run a clipping agency, captions are part of every clip you ship: someone has to transcribe, time, style and burn them. Stream clips are the worst case: crosstalk, game noise, slang, shouted proper nouns.
One submit per clip, then poll
caption.sh is an async job API. Hand it the clip (pass a public URL, or upload a file via the signed-URL flow in the docs), set the caption style once, and poll until the job is done. The result is a new MP4 with word-timed, styled captions burned in, ready to post. Transcription, word timing and rendering all happen server-side.
# caption a clip straight from your clipping pipeline
KEY=$CAPTION_API_KEY
resp=$(curl -s -X POST https://api.caption.sh/v1/videos \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"source_url":"https://cdn.example.com/clip.mp4","options":{"font":"dynapuff","size":"large","highlight":true}}')
job=$(echo "$resp" | jq -r .job_id)
if [ -z "$job" ] || [ "$job" = "null" ]; then echo "submit failed: $resp"; exit 1; fi
deadline=$((SECONDS + 600))
status=""
while [ $SECONDS -lt $deadline ]; do
resp=$(curl -s https://api.caption.sh/v1/jobs/$job -H "Authorization: Bearer $KEY")
status=$(echo "$resp" | jq -r .status)
[ "$status" = "done" ] && break
[ "$status" = "error" ] && { echo "job failed: $resp"; exit 1; }
sleep 5
done
[ "$status" = "done" ] || { echo "gave up waiting for job $job"; exit 1; }
curl -sL -H "Authorization: Bearer $KEY" \
https://api.caption.sh/v1/jobs/$job/result -o captioned-clip.mp4Jobs are independent, so an agency clipping a six-hour stream can run highlights in parallel within the per-key throughput limits (a 429 means back off and retry) instead of queueing them through an editor. The API documents no webhook surface: you poll GET /v1/jobs/{id} until the status flips, with your own timeout, and the result endpoint redirects to a signed download URL; results are stored for 24 hours and then deleted. Because the captions are part of the pixels, no platform or player can drop or restyle them, which matters when the same clip goes to TikTok, Reels and Shorts.
Built for noisy source audio
- Stream audio is noisy: crosstalk, fast delivery, background game audio. The honest evaluation is to run a real highlight through and read the transcript yourself.
- Profanity controls are per job: censor_captions masks words in the text (F***), censor_audio mutes them in the audio, independently. Useful when a clip needs to be brand-safe but the streamer was not.
- Outline or backdrop decoration keeps captions legible over gameplay, and word highlight keeps the pacing readable.
- Pricing is $0.10 per minute, prepaid. Clips are short, so per-clip cost stays in cents.
If clips are your product or your service, the fastest evaluation is to get an API key at caption.sh and run one real highlight through. The output speaks for itself.