Skip to main content
A product video in one language reaches a fraction of its audience. Dubbing is a timing problem more than a translation problem: each line has to fit the seconds the original took. This pipeline translates with the seconds in the prompt, voices each line, speeds a long line up by at most 35%, and then listens to its own work: it transcribes every dubbed line and flags the ones that do not say what they should. Two languages for a 7-second ad cost 2 cents.

Build it in your project

Paste this line into your agent (Claude Code, Codex, Cursor, OpenCode, Cline). It sets up your key, then builds the pipeline in your project:

The code

One file per language. Both read RUNCRATE_API_KEY from the environment; nothing secret is in the code.

What the proof run cost

The Python file on the 7-second ad from the video ad recipe, into Spanish and German. Measured on 2026-10-23 against api.runcrate.ai; costs are what the account was billed, read from each response’s X-LLM-Cost header or usage.cost. The TypeScript file: $0.0200 in 18 s. On that run the check flagged one line in each language: both were lines sped up to the 1.35x cap, heard back as “Montente” and “bleibe”.

Scale it

  • Every language is independent: run them in parallel, or one job per language.
  • Long videos: segments are short, so a 10-minute video is about 150 lines; the cost is the TTS characters plus two transcriptions of the audio.
  • Review only what the check flags: the word-match score is in run.json for every line.

Gotchas found in the proof run

  • ResembleAI/chatterbox-multilingual mangled Spanish and German when given only the text (“sostenable Canoistra”); it takes no language parameter. Qwen3-TTS read the same lines cleanly, so the recipe uses it.
  • A lip-synced talking head was tried and left out: kuaishou/kling-avatar-v2 answered 502 three times, and Seedance 2.0 Fast refused a photographic portrait with reference audio as sensitive (E005). It goes in when it runs. When you add one: Kling Lip Sync and Kling Avatar v2 make a clip as long as the audio or video you send, so duration is ignored. Runcrate measures your input when you submit and needs that clip’s cost free in your balance, with a second or so of margin; you’re charged only for the clip’s real length, and a balance too low is refused with 402 and "code": "video_hold_unaffordable". See video generation.
  • Music under the voice is lost: this replaces the audio track. Separate the stems first (an open source-separation model on a GPU job) if the original has a score.
  • The 1.35x cap is where speech starts to slur; the back-transcription check is how you find those lines.