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:
- Go to
Stream › Videosand open the video. - Open the
Captionstab. - Click
Add Captionsand choose the language. - Choose
Generate captions with AIand 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.
- Pick a language tag in BCP 47 format, for example
en,de, oren-GB. - Send a
PUTrequest to/client/v4/accounts/ACCOUNT_ID/stream/VIDEO_UID/captions/enonapi.cloudflare.com. - Set the header
Authorization: Bearer API_TOKEN. - Send the VTT file as a multipart form field named
file. - 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.
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.
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
POSTrequest to the same captions address, with/generateat the end. - While Stream works, the status is
inprogress. When it finishes, the status isready. 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
defaultTextTrackoption 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.
- In Cloudflare, go to
My Profile › API Tokensand create a custom token. Add the permissionAccount › Stream › Editand limit the token to one account. Copy the account ID from the account overview page. - In CaptionsHero, go to
Settings › Integrations. Under Cloudflare Stream, paste theAccount IDand theAPI token. ClickConnect Cloudflare. - Open a project and go to its
Upload videospage. InImport from Cloudflare, clickBrowse videos. - Search the library. Select up to 25 videos. Set the spoken language for the selection, or change it for one video. Click
Import selected. - Wait for the status
Ready to caption. ClickOpen. - Click
Create subtitles. Choose a language. Then chooseGenerate with AI,Import subtitle file, orStart blank. Repeat for each language. - The owner assigns an editor and a reviewer to each track. The editor corrects the text and clicks
Submit for review. - The reviewer leaves comments on exact lines. The reviewer clicks
Request changesorApprove. - The owner clicks
Publish to Cloudflareon the track row, or in the editor header. A dialog shows the account, the video, and the language. ClickPublish.
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.
- Upload the video to a CaptionsHero project.
- Make the subtitles:
Generate with AI,Import subtitle file(SRT or WebVTT), orStart blank. - Review and approve each language. On Team and Studio plans, use the editor and reviewer assignments for this step.
- In the editor, open the track menu (
More track actions). ClickDownload WebVTT. For an approved track, you can clickExport official WebVTTinstead. - 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 Stream | CaptionsHero | |
|---|---|---|
| Caption format | WebVTT only | Import SRT and WebVTT. Export SRT and WebVTT. |
| Tracks per video | One for each language | A track for each language, with its own editor and reviewer |
| Automatic captions | 12 languages, in the spoken language | AI transcription and AI translation, 82 languages |
| File or video size | 10 MB for each caption file. 30 GB for each video upload by default. | 4 GB and 4 hours for each video imported from Stream |
| Plan | No 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.