2026-11-02 · 4 min read
A Caption API for Screen Recordings
Product walkthroughs, bug reports and tutorial recordings all share a problem: the narration carries the meaning, and viewers often watch with the sound off or struggle to catch every word over a compressed microphone. Burned in captions keep the narration readable without asking the viewer to turn anything on.
If you produce these recordings regularly, captioning them one by one in an editor does not scale. The caption.sh API takes a video URL and returns the same video with the captions rendered into the frames, so it fits into whatever export script you already have.
The captioning workflow
Submit the recording, then poll the job until the render finishes. This example writes the captioned file next to the original.
import requests, time
KEY = "YOUR_CAPTION_API_KEY"
H = {"Authorization": f"Bearer {KEY}"}
API = "https://api.caption.sh/v1"
def caption_video(source_url, out_path):
r = requests.post(f"{API}/videos", headers=H,
json={"source_url": source_url, "options": {}},
timeout=30)
if r.status_code == 402:
raise RuntimeError("out of credits, top up first")
r.raise_for_status()
job_id = r.json()["job_id"]
deadline = time.time() + 60 * 60
while time.time() < deadline:
time.sleep(15)
job = requests.get(f"{API}/jobs/{job_id}", headers=H, timeout=30).json()
if job["status"] == "done":
break
if job["status"] == "error":
raise RuntimeError(f"render failed: {job}")
else:
raise RuntimeError("render did not finish in time")
mp4 = requests.get(f"{API}/jobs/{job_id}/result", headers=H, timeout=60)
open(out_path, "wb").write(mp4.content)Practical notes
- Submissions are rate limited per API key. A 429 response means wait a moment and retry, it does not mean the job failed.
- Rendering is prepaid at $0.10 per minute of video. A 402 response means the balance is empty, so top up before retrying.
- Every render needs a bounded poll loop with three exits: done, error, and your own timeout. Do not poll forever.
- The API documents no webhook surface, so polling is the intended way to learn a job finished.
For long recordings, split the file before submitting if you only need certain chapters captioned, since billing is per minute of rendered video. The captioned output is a normal mp4, so it drops back into your editor, LMS or help center without special handling.