How to add subtitles to Cloudflare Stream videos

Upload a WebVTT file with the Stream API, or make AI captions. Then see how to add many languages with review and approval.

Facts checked on 2026.10.13. Sources

The short answer

Cloudflare Stream takes subtitles as WebVTT files. You add a file to a video with the Stream API, one file for each language. Stream can also make AI captions in 12 languages.

For one language, that is often enough. For many languages, or when someone must review the text before viewers see it, use a subtitle tool to make the files. CaptionsHero can also import videos from Stream and publish approved subtitles back. That integration is on the Studio plan.

Add subtitles in Cloudflare Stream

Stream has two ways to add captions: you upload a file, or Stream makes AI captions. The video must exist in Stream first. Each video holds one caption track for each language.

In the dashboard

The Stream docs describe captions only through the API. They list no dashboard steps for captions.

A 2024 Cloudflare blog post shows one dashboard path, for AI captions. The labels may have changed since then:

  1. Go to Stream › Videos and open the video.
  2. Open the Captions tab.
  3. Click Add Captions and choose the language.
  4. Choose Generate captions with AI and save.

The docs do not say if the Captions tab accepts a WebVTT file. Look for a file option in your dashboard. If you find none, use the API.

With the API

You need a Cloudflare API token, your account ID, and the video UID. Stream accepts only WebVTT. Convert an SRT file first.

  1. Pick a language tag in BCP 47 format, for example en, de, or en-GB.
  2. Send a PUT request to /client/v4/accounts/ACCOUNT_ID/stream/VIDEO_UID/captions/en on api.cloudflare.com.
  3. Set the header Authorization: Bearer API_TOKEN.
  4. Send the VTT file as a multipart form field named file.
  5. A good reply has "status": "ready". The player now offers the language.

The same API lists the captions of a video (GET), returns one VTT file (GET with /vtt at the end), and deletes a track (DELETE). The TypeScript SDK and the Workers Stream binding offer the same actions. See the Stream caption docs and the API reference.

captions-de.vtt
WEBVTT00:00:01.000 --> 00:00:04.200Wer hat die spanische Datei?00:00:04.600 --> 00:00:07.000Mina hat sie. Sie hat sie zurückgeschickt.
A WebVTT file that you can upload as the de track.

Automatic captions

Stream turns speech into captions with AI. The video must be ready. Tell Stream the language that people speak in the audio.

  • Languages: Czech, Dutch, English, French, German, Italian, Japanese, Korean, Polish, Portuguese, Russian, and Spanish.
  • API: send a POST request to the same captions address, with /generate at the end.
  • While Stream works, the status is inprogress. When it finishes, the status is ready. The label ends with "(auto-generated)".
  • If the status is error, delete the caption and make it again.
  • Cloudflare's changelog says generated captions are free for video stored in Stream.

Stream makes captions in the spoken language only. The Stream docs list no translation feature. A Cloudflare blog post from 2024 tests translation with Workers AI and calls it an experiment that is not ready for production.

Where the built-in ways stop

If you need one language and the AI text is good, use the AI captions and stop here. Cloudflare lists no extra price for them. When the AI makes a mistake, do this: download the file with the /vtt request, fix it in a text editor, and upload it again. Uploading replaces the generated track.

The built-in ways stop in these cases:

  • Many languages. Stream makes no translations. You must get each file from a translator or another tool.
  • Editing. The docs describe no caption editor. To change one line, you replace the whole file.
  • Review before viewers see it. A caption reaches viewers when its status is ready. The docs describe no assignment, review, or approval step.
  • Other formats. Stream accepts only WebVTT. SRT files from translators need a conversion.
  • Accessibility details. The docs describe no SDH setting. They call the AI output "closed captions". To choose which language starts on, use the defaultTextTrack option of the Stream Player.

Add subtitles with CaptionsHero

CaptionsHero adds three things to Stream's own AI captions. First, AI translation into many languages (82 languages for AI transcription and translation). Second, an editor and a reviewer for each language. Third, an approval step before anything reaches Stream.

For videos in your Stream library (Studio plan)

Only an organization owner can connect Cloudflare. Connect once, then import videos from any project.

  1. In Cloudflare, go to My Profile › API Tokens and create a custom token. Add the permission Account › Stream › Edit and limit the token to one account. Copy the account ID from the account overview page.
  2. In CaptionsHero, go to Settings › Integrations. Under Cloudflare Stream, paste the Account ID and the API token. Click Connect Cloudflare.
  3. Open a project and go to its Upload videos page. In Import from Cloudflare, click Browse videos.
  4. Search the library. Select up to 25 videos. Set the spoken language for the selection, or change it for one video. Click Import selected.
  5. Wait for the status Ready to caption. Click Open.
  6. Click Create subtitles. Choose a language. Then choose Generate with AI, Import subtitle file, or Start blank. Repeat for each language.
  7. The owner assigns an editor and a reviewer to each track. The editor corrects the text and clicks Submit for review.
  8. The reviewer leaves comments on exact lines. The reviewer clicks Request changes or Approve.
  9. The owner clicks Publish to Cloudflare on the track row, or in the editor header. A dialog shows the account, the video, and the language. Click Publish.

CaptionsHero uploads the approved version to Stream as WebVTT, in the language of the track. If Stream already has captions in that language, the dialog says so, and the button changes to Replace captions. That includes AI captions that Stream made. Stream keeps one caption file for each language.

If someone edits an approved track later, the track shows Changes not published. The owner clicks Publish update to send the new version.

Software can import too. Send one video for each request to POST /api/v1/projects/{projectId}/videos/cloudflare-import with an API key that has the videos:create scope.

For any other video, or any other plan

Publish to Cloudflare works only for videos that you imported from Stream, on the Studio plan. For every other video, make the files in CaptionsHero and upload them to Stream yourself.

  1. Upload the video to a CaptionsHero project.
  2. Make the subtitles: Generate with AI, Import subtitle file (SRT or WebVTT), or Start blank.
  3. Review and approve each language. On Team and Studio plans, use the editor and reviewer assignments for this step.
  4. In the editor, open the track menu (More track actions). Click Download WebVTT. For an approved track, you can click Export official WebVTT instead.
  5. Upload each file to Stream with the API steps above. Use a different language tag for each file.

Check the file before you upload

A broken file can show wrong text or wrong timing in the player. Check each VTT file before you send it. The free tools below run in your browser. Your file stays on your computer.

To learn how SRT and WebVTT differ, read Subtitle formats explained. To check line length, reading speed, and timing, read the subtitle QC checklist.

Limits and plans

Cloudflare StreamCaptionsHero
Caption formatWebVTT onlyImport SRT and WebVTT. Export SRT and WebVTT.
Tracks per videoOne for each languageA track for each language, with its own editor and reviewer
Automatic captions12 languages, in the spoken languageAI transcription and AI translation, 82 languages
File or video size10 MB for each caption file. 30 GB for each video upload by default.4 GB and 4 hours for each video imported from Stream
PlanNo plan limit for captions in the docs. Stream bills by minutes stored and delivered.Cloudflare import and publishing: Studio. Assignments and review: Team and Studio. Editor and file export: all plans.

Prices of CaptionsHero plans: Solo is free. Solo Pro costs $29, Team $149, and Studio $399 for each month. The price is flat for each organization.

Cloudflare may charge for video delivery. The CaptionsHero import panel also says so.

Common questions

Can I upload an SRT file to Cloudflare Stream?

Not directly. Stream reads WebVTT only. Convert the SRT file to VTT first. The conversion keeps the text and the times.

How large can a caption file be?

10 MB for each file. Contact Cloudflare support if you need more. A normal subtitle file is far smaller than this.

Can a Stream video have subtitles in two languages?

Yes. Add one file for each language tag, for example en, fr, and de. Two files with the same tag are not allowed. A second upload with a tag replaces the first.

How does a viewer pick a language?

Stream builds a language name from each tag, such as Deutsch for de, and the player offers it for selection. To start the video with one language on, add defaultTextTrack with the language tag to the player address.

Does Stream make subtitles automatically?

Yes, for 12 spoken languages. The result is a transcript of the audio in the same language. Another language needs a translation from another source.

Can I change a caption after I upload it?

Only by replacing it. Stream has no editor for caption text. Edit the file in a subtitle editor, then upload it again with the same language tag.

Does CaptionsHero change my original video in Stream?

No. An import copies the video into a CaptionsHero project. To copy it, CaptionsHero turns on the MP4 and audio downloads of that video in Stream. It does not change the picture or sound, and it does not delete the video. Publishing adds or replaces the caption file for one language.

Subtitles in many languages, approved before they go live

Import your Stream videos, assign each language to an editor and a reviewer, and publish the approved version.

Free forever plan. No card required. No sales call.

  • Every language gets a translator and a reviewer
  • Feedback on the exact line, not in an email thread
  • Only the approved version ships
  • See who's holding up which language
  • AI drafts in 82 languages, or bring your SRT
  • Private, in the browser, nothing to install

Sources