Use WebVTT for anything on the web, since the HTML <track> element requires it. Use SRT when you’re uploading to a platform or editor that asks for it, or when you want the simplest possible file that nearly any software can read. Converting SRT to VTT is safe and lossless in practice. Converting VTT to SRT can lose positioning, styling, speaker tags and notes, so keep the VTT as your master if you’ve used those features.
The same captions in both formats
SRT (SubRip):
1
00:00:01,000 --> 00:00:03,500
Welcome back to the show.
2
00:00:04,000 --> 00:00:06,250
<i>Today</i> we're talking about caching.
WebVTT:
WEBVTT
00:00:01.000 --> 00:00:03.500
Welcome back to the show.
00:00:04.000 --> 00:00:06.250
<i>Today</i> we're talking about caching.
The basic differences are visible at once: VTT has a header, a dot rather than a comma before milliseconds, and no need for cue numbers. If you only have plain text captions, this is all that separates them. A converter’s whole job is often these three changes.
How they differ
| Feature | SRT | WebVTT |
|---|---|---|
| Header | None | Required: WEBVTT on the first line |
| Time separator | Comma: 00:00:01,000 | Dot: 00:00:01.000 |
| Hours in timestamps | Required | Optional: 00:01.000 is valid |
| Cue identifiers | Sequential number, expected | Optional, can be any text |
| Formal specification | None, a de facto format | W3C WebVTT specification |
| Positioning | No standard, {\an8} by convention | Built-in cue settings |
| Styling | Basic tags by convention | Tags, plus CSS through STYLE blocks |
| Comments | None | NOTE blocks |
| Speaker tags | None | <v Name> |
| Encoding | Varies, often legacy | UTF-8 only |
& and < in text | Usually literal | Must be escaped: &, < |
The lack of a specification is the source of most SRT problems. Parsers vary in how they handle tags, encodings and blank lines, because no document says what’s correct.
What VTT can do that SRT cannot
Here’s a VTT file using these features:
WEBVTT - Episode 12
STYLE
::cue(.warning) { color: yellow; }
NOTE Reviewed by the editor on 3 March
intro
00:01.000 --> 00:03.500 line:0 position:20% size:60% align:start
<v Priya>Hello and <c.warning>welcome</c> & thanks for joining.
00:04.000 --> 00:06.000
<v Tom>Thanks, it's good to be here.
Cue settings come after the timing, on the same line:
| Setting | Values | Effect |
|---|---|---|
line | A number, or 0% to 100% | Vertical position. line:0 is the top |
position | 0% to 100% | Horizontal position of the cue box |
size | 0% to 100% | Width of the cue box |
align | start, center, end | Text alignment within the box |
vertical | rl, lr | Vertical text, for scripts that need it |
Their main practical use is moving captions out of the way when there’s on-screen text at the bottom.
Inline tags include <b>, <i>, <u>, <c.class> for CSS classes, <v Name> for voices, <lang> for language, <ruby> for ruby text, and timestamp tags such as <00:00:02.000> for word-by-word reveal.
A cue’s text can’t contain a blank line, in either format, because the blank line ends the cue. It’s a common cause of cues getting cut in half.
Which players need which
Web browsers. The HTML <track> element uses WebVTT. MDN’s documentation says that tracks “are formatted in WebVTT format”. SRT in a <track> won’t work without first being converted, and that’s the most common reason this comes up. The file must also be same-origin, or the <video> needs a crossorigin attribute, and a subtitles track must set srclang:
<video controls src="talk.mp4">
<track kind="subtitles" src="talk.vtt" srclang="en" label="English" default>
</video>
Serve the file as text/vtt. If captions silently don’t appear, check the MIME type and any CORS headers first.
HLS streaming for Apple devices. Apple’s HLS authoring specification states that subtitles “MUST be WebVTT” or IMSC1 in fMP4, and on tvOS WebVTT only.
YouTube. Its help page accepts both. It lists SRT as a basic format, and says that no style markup is recognized in it. It lists WebVTT as an advanced format with an initial implementation, which supports positioning and limits styling to bold, italic and underline. So uploading a carefully styled VTT won’t keep everything.
Desktop players. VLC’s feature page lists SubRip among its supported subtitle formats. Support for VTT in other desktop players and editors varies, so test your own setup.
Editing software and social platforms. Requirements vary and they change over time. Check the current help page for the product you use. If a platform doesn’t say, SRT is usually the safer guess.
Converting safely
SRT to VTT
This direction usually loses nothing, because VTT does everything SRT does. Three details matter, however, and they’re the difference between a converter and a find-and-replace.
- Add the header, followed by a blank line.
- Change the comma to a dot only in timing lines. A global replace would alter commas in your dialogue. Don’t do that.
- Escape
&and<in the text. A line such asFish & chipsorx < 5is fine in SRT and invalid in VTT, and some parsers then drop or misread it.
Check the encoding too. SRT files from old tools are often Windows-1252 or similar, and VTT must be UTF-8. If café turns into café or caf�, the source encoding was misread. Convert it to UTF-8 first.
VTT to SRT
This direction loses things. We ran the sample above through ffmpeg and through our converter:
| Feature in the VTT | ffmpeg output | Our VTT to SRT |
|---|---|---|
STYLE and NOTE blocks | Dropped | Dropped |
<c.class> tags | Removed | Removed |
<v Priya> | Removed, speaker lost | Becomes Priya: by default |
& | Decoded to & | Decoded to & |
| Cue settings | Dropped | Rough position kept as an {\an7} style tag |
The {\an} tags aren’t standard SRT, though many players read them. If your target ignores them, they might show up as literal text. So decide based on where the file is going, and check a cue with position settings by eye.
For a command-line conversion of many files, this is a reliable approach:
ffmpeg -i input.srt output.vtt
ffmpeg -i input.vtt output.srt
We ran both. In the SRT to VTT direction, ffmpeg removed a <font> tag and a {\an8} tag, kept <b> and left a bare & unescaped, so check its output if your text has ampersands.
After any conversion
- Open the result in the player you’ll be using, not only in a text editor.
- Check the first cue, the last cue and any cue with an
&, a<, or an accented letter. - Confirm the number of cues matches. Text after a stray blank line is a usual culprit.
- Validate that the timing hasn’t drifted. Conversion doesn’t change timing, so if it’s out of sync, the source was off.
Common faults in the wild
Overlapping cues. A cue that starts before the previous one ends. In a browser, both may display at once, stacking up. This is common in auto-generated captions.
Rolling captions. Files that repeat the previous line in every new cue, with inline timestamps, which is YouTube’s download style. Our guide on cleaning auto-generated transcripts covers how to fix that.
A BOM or missing header. A VTT with anything before WEBVTT other than a byte order mark will be rejected entirely. With no header at all, the browser ignores the file with no visible error. Check the network tab and the console.
A dot in SRT or a comma in VTT. Some players are forgiving. Others skip cues without any warning.
Our converters, and when to use something else
SRT to VTT and VTT to SRT run in your browser and handle the timing, header, tags and escaping described above. For example, ours turned Fish & chips into Fish & chips going to VTT, and back again going to SRT. The SRT to Text and VTT to Text tools strip everything down to the words. They suit individual files and quick fixes. They don’t touch timing, so they can’t sync subtitles to a re-edited video, and they won’t handle formats such as ASS or TTML. For timing work, use Subtitle Edit or Aegisub. For batch jobs, use the ffmpeg commands above.