The minimal markup
A video with one subtitle track looks like this in HTML: a video element with controls, a source element for the MP4, and a track element with kind="subtitles", src pointing at the .vtt file, srclang set to the language code (for example "es"), and label set to what viewers should see in the menu ("Español"). Add the default attribute to one track if you want it showing when the page loads.
Each attribute matters:
- kind
- subtitles (translation or transcription of speech for viewers who can hear), captions (also speaker names and sounds, for deaf and hard-of-hearing viewers), descriptions, chapters or metadata.
- src
- URL of the WebVTT file.
- srclang
- Language of the track as a language tag, such as en, es, pt-BR or zh-Hans.
- label
- The name shown in the player's menu. Write it in the track's own language.
- default
- Turns this track on initially. Use it on one track at most.
It has to be WebVTT
Browsers read WebVTT for track elements, not SRT. A WebVTT file starts with the line WEBVTT, uses a full stop before the milliseconds in timestamps, and is saved as UTF-8. If you have an SRT, convert it; converting SRT to VTT shows the hand method and free tools, and what a VTT file is explains the format. The VTT generator produces VTT directly from the video's speech.
Several languages
Add one track element per language, each with its own srclang and label. The browser lists them all in its captions menu. Keep labels in each language's own name (Deutsch, 日本語, Français) so speakers recognise them. Multilingual video on your website covers where to put language choices on the page and how to handle a separate dubbed audio version.
A course builder hosts lesson videos on her own server. Each lesson has lesson-04.mp4 and three files: lesson-04.en.vtt, lesson-04.es.vtt and lesson-04.pt-br.vtt. The track labels read English, Español and Português (Brasil); English carries the default attribute.
Server and cross-origin details
Two server issues cause most "subtitles don't show" reports:
- Content type. Serve .vtt files as text/vtt. Some servers send them as plain text or as a download, and browsers then ignore the track.
- Cross-origin. If the VTT lives on a different domain or CDN from the page, the browser blocks it unless the video element has the crossorigin attribute and the VTT's server sends an Access-Control-Allow-Origin header that permits your site.
Open the browser's developer tools and check the network tab: a 404, a wrong content type or a CORS error is visible there in seconds.
Styling with ::cue
CSS can style cue text through the ::cue pseudo-element: colour, background, font family, size, weight and a few related properties. You can't move cues around freely with CSS; position comes from cue settings inside the VTT file. On some phones in full screen, the operating system draws captions itself and applies the user's own caption settings, which is good for accessibility, so don't rely on custom styles being visible everywhere. An accessible video player lists what else a player needs: keyboard controls, focus states and caption contrast.
Making the VTT files with mydubly
Upload the video to the subtitle generator; it stays on your device and only the audio is sent. Every run returns SRT and VTT, in the spoken language or translated into one of 21 languages, for 1 credit per minute. Run the file once per language and name the outputs by language code so the markup stays readable. Translations into Chinese come in Simplified Chinese, so label that track zh-Hans or zh-CN.
Limits and pitfalls
- Automatic files have no speaker names or sound descriptions. Label them kind="subtitles"; edit them before calling them captions. Captions vs subtitles explains the difference.
- Cues come one line each with no fixed length limit; long cues wrap and can cover a lot of the picture, so split them for small screens.
- The default attribute doesn't override a viewer's settings in every browser. Test on the browsers your audience uses.
- Custom players built on JavaScript libraries usually read the same track elements or a similar list of VTT files; check their documentation.
- Publishing a transcript beside the video helps readers who prefer text; publishing transcripts on your website covers layout.
Testing before you ship
A quick test plan catches nearly every problem:
- Load the page in two browsers and on a phone, and open the captions menu. Every language should be listed with the right label.
- Turn each track on and check the first line, a line in the middle and the last line against the speech.
- Watch the network tab for a 200 response and the text/vtt content type on each file.
- Try the video in full screen on the phone; captions should still appear, possibly in the device's own style.
- Tab to the player with the keyboard and turn captions on without a mouse.
If the page serves a dubbed version too, check that the captions offered match the audio. A Spanish dub with English captions switched on by default confuses viewers. Making a video with two audio tracks explains how dual-audio files behave in players, and video file not supported covers playback failures that look like caption problems but aren't.
Frequently asked questions
Can I use an SRT file in an HTML5 track element?
No. Browsers read WebVTT for track elements. Convert the SRT to VTT, or generate VTT directly.
Why don't my HTML5 subtitles show?
Check the network tab: the VTT may be missing, served with the wrong content type, or blocked by cross-origin rules. Also confirm the file starts with WEBVTT.
What's the difference between kind subtitles and kind captions?
Captions include speaker identification and meaningful sounds for viewers who can't hear the audio. Subtitles cover the speech only.
How do I add subtitles in several languages?
Add one track element per language, each with its own srclang and label.
Can I style HTML5 subtitles with CSS?
Partly. The ::cue pseudo-element styles colour, background and fonts. Position comes from cue settings in the VTT file, and some devices apply the user's own caption style.
Which MIME type should a VTT file have?
text/vtt.