Found me on Upwork? If you found me through Upwork and want to work together, please contact me through Upwork. Messages from Upwork clients sent outside Upwork will not be answered.
Comparison🎬 Captioning & Subtitles

SRT vs WebVTT: Technical Differences and How to Convert

SRT uses a comma for milliseconds; WebVTT uses a period, adds a WEBVTT header, cue positioning and CSS ::cue. One ffmpeg command converts between them.

Dao Huy (Lucas)7 min read8 sections · side-by-side table
SRT vs WebVTT: Technical Differences and How to Convert

💡 SRT and WebVTT carry the same timed-text data, but differ in three ways: WebVTT requires a WEBVTT header on line 1, swaps SRT's comma millisecond separator for a period (00:00:11,500 becomes 00:00:11.500), and adds optional per-cue positioning settings and a CSS STYLE block. Convert with ffmpeg -i in.srt out.vtt - no video re-encode needed.

Key takeaways

  • The one character that breaks everything: SRT uses a comma for milliseconds (00:00:11,500); WebVTT uses a period (00:00:11.500).
  • WebVTT requires WEBVTT on line 1. SRT has no header at all.
  • WebVTT cue settings (line:, position:, size:, align:) add per-cue positioning that SRT cannot express.
  • A STYLE block with ::cue CSS applies global font and colour rules to WebVTT; SRT has no native styling mechanism.
  • Convert: ffmpeg -i in.srt out.vtt (single file); seconv *.srt WebVTT --output-folder:out/ --overwrite for batches.

What is the actual technical difference between SRT and WebVTT?

I deliver subtitle files in both formats regularly: SRT to clients who need a quick plain-text deliverable accepted by every player and NLE, WebVTT to web developers who need an HTML5 <track> element with precise positioning. Both formats share the same core model - a numbered sequence of cues, each with a start time, end time, and text lines - but WebVTT is a formal W3C standard with features SRT never had.

FeatureSRTWebVTT
HeaderNoneWEBVTT (required, line 1)
Milliseconds separatorComma (,)Period (.)
Per-cue positioningNoneline:, position:, size:, align:, vertical:
CSS stylingNoneSTYLE block with ::cue selector
Inline span tagsLimited (player-dependent)Defined: <b>, <i>, <v>, <c>
Typical delivery targetEverywhere (broadest compatibility)Web video, YouTube, HTML5 <track>

Here is the same subtitle event in SRT and then in WebVTT. The text content is identical; the mechanics differ:

SRT:

1
00:00:10,000 --> 00:00:14,500
Note the comma after the seconds.
A period here breaks every SRT parser.

2
00:00:15,000 --> 00:00:18,200
Cues are separated by a blank line.
No header line appears above cue 1.

WebVTT (same content):

WEBVTT

1
00:00:10.000 --> 00:00:14.500
Note the period after the seconds.
A comma here breaks every WebVTT parser.

2
00:00:15.000 --> 00:00:18.200
Cues are still separated by a blank line.
The WEBVTT header and a blank line precede cue 1.

The structural differences:

  • WEBVTT header: present in WebVTT, absent in SRT.
  • Blank line after the header: required in WebVTT before the first cue.
  • Milliseconds separator: , in SRT vs . in WebVTT. This single character is the most common source of parser errors when copying timestamps between formats.

WebVTT cue settings: per-cue positioning

WebVTT lets you append positioning settings to each cue's timing line. I use these when a web developer needs specific subtitle placement rather than the player's default bottom-center rendering. SRT has no equivalent field.

WEBVTT

subtitle-01
00:00:10.000 --> 00:00:14.500 line:85% position:50%,center size:80% align:center
This cue sits near the bottom, horizontally centered, max 80% wide.

subtitle-02
00:00:15.000 --> 00:00:18.200 line:10% position:50%,center
This cue sits near the top of the frame.

subtitle-03
00:00:19.000 --> 00:00:22.000 vertical:rl line:10%
Vertical text runs right-to-left down the left side.

The key settings:

  • line:: vertical position as a percentage (0% = top, 100% = bottom) or a line-number integer. Negative integers count from the bottom edge.
  • position:: horizontal position as a percentage, with optional alignment (line-left, center, line-right).
  • size:: width of the cue box as a percentage of the video width.
  • align:: text alignment within the cue box: start, center, end, left, or right.
  • vertical:: vertical text direction. rl = right-to-left, lr = left-to-right. Used for CJK vertical scripts.

How do I add CSS styling with the WebVTT STYLE block?

The STYLE block goes before the first cue and applies CSS to all cues via the ::cue pseudo-element. Two hard constraints from the W3C spec that have caught me: the stylesheet content cannot contain blank lines (a blank line ends the block), and the string --> must not appear inside it.

WEBVTT

STYLE
::cue {
  font-family: Arial, sans-serif;
  font-size: 1.4rem;
  color: #FFFFFF;
  background-color: rgba(0, 0, 0, 0.75);
}
::cue(b) {
  font-weight: bold;
  color: #FFD700;
}
::cue(v[voice="Narrator"]) {
  color: #ADD8E6;
}

1
00:00:10.000 --> 00:00:14.500
This is <b>bold yellow</b> text.

2
00:00:15.000 --> 00:00:18.200
<v Narrator>This line uses the Narrator voice style.</v>

Key points:

  • ::cue targets all cues globally. Scoped selectors like ::cue(b) target cues containing a <b> span; ::cue(v[voice="..."]) targets voice spans by speaker name.
  • No blank lines inside the STYLE block: the parser treats the first blank line as the end of the stylesheet.
  • Browser support for ::cue is solid in Chrome, Firefox, and Safari. ::cue-region is defined in the W3C spec but not yet implemented in any browser as of 2026.
  • STYLE blocks are silently discarded when converting to SRT. If styling is critical for delivery, burn the subtitles into the video with ffmpeg instead of relying on player-rendered ::cue.

How do I convert SRT to WebVTT, and back?

For a single file, ffmpeg is the fastest path. It auto-detects both formats by extension and converts as a pure text operation - the video stream is never decoded:

# SRT to WebVTT
ffmpeg -i in.srt out.vtt

# WebVTT to SRT
ffmpeg -i in.vtt out.srt

What happens internally: ffmpeg reads SRT via the subrip demuxer and writes WebVTT via the webvtt encoder (or the reverse). The comma-to-period substitution is automatic. No extra flags needed; the format is inferred from file extensions.

For a folder of files, I use SeConv. Format names are case-sensitive:

# Convert a folder of SRT files to WebVTT
seconv *.srt WebVTT --output-folder:out/ --overwrite

# Convert a folder of VTT files to SRT
seconv *.vtt SubRip --output-folder:out/ --overwrite

# List every supported format name
seconv formats

SeConv writes the full three-part timestamp (HH:MM:SS.mmm) in WebVTT output. The W3C spec allows the hours field to be omitted when it is 0, but some older parsers expect the full form, so I always use it.

What gets lost when you convert WebVTT back to SRT?

SRT to WebVTT is lossless: the converter adds the header and swaps the comma for a period. The reverse conversion silently drops everything SRT cannot represent:

  • Cue settings: line:, position:, size:, align: are stripped. SRT has no field for positioning metadata.
  • STYLE block: the entire CSS block is discarded. No font, colour, or background setting survives.
  • REGION and NOTE blocks: dropped.
  • Named cue identifiers: if VTT cues use string identifiers (like subtitle-01), SeConv renumbers them as integers; ffmpeg preserves them if they are already numeric.

The timed text content - the actual words - survives intact in both directions. If your VTT file has no cue settings or STYLE block, round-tripping to SRT and back is safe.

What can I handle myself, and when does a specialist help?

The mechanical conversion is something any developer or editor can do with the commands above. ffmpeg and SeConv are free, well-documented, and handle the conversion correctly. I convert between these formats routinely and have never needed external help for a format change alone.

Where things get more involved:

  • If the source was machine-generated (Whisper auto-captions or YouTube's auto-track), timing and reading speed usually need a human review pass before delivery, regardless of format.
  • If the delivery is a translated subtitle track, the translated lines often run longer or shorter than the original, requiring timing adjustments to stay within reading-speed limits. That is the craft behind professional subtitle translation: fitting translated text into the original timing at a readable pace.
  • If the destination is a broadcast or streaming platform requiring SCC, SMPTE-TT, or MCC, neither SRT nor WebVTT is the final deliverable and a broadcast caption workflow applies.

For a plain format swap on a clean, human-edited subtitle file, the commands above are everything you need.

FAQ

Can I open a WebVTT file in Subtitle Edit?

Yes. Subtitle Edit reads and writes WebVTT natively. Open it normally from File > Open, edit as usual, and save or export to any format from the Save As dialog. SeConv's batch mode also accepts VTT as an input format.

Why does my browser show unstyled captions even though I have a STYLE block?

Two common causes: the STYLE block contains a blank line (the parser stops reading the stylesheet at the first blank line and treats the rest as a cue), or you are loading the page from a file:// URL, which blocks ::cue rendering in some browsers for local files. Check that there are no blank lines anywhere inside the STYLE block content.

Does YouTube preserve WebVTT cue positioning and STYLE CSS after upload?

No. YouTube Studio accepts both SRT and WebVTT, but internally converts to its own format. Cue positioning settings and STYLE block CSS are not preserved in playback. For YouTube, upload SRT for simplicity; the cue positioning advantages of WebVTT are not available on the platform.

Is the hours field optional in WebVTT timestamps?

The W3C spec allows MM:SS.mmm when the hours field is 0 (for example 00:11.500). SRT always requires HH:MM:SS,mmm. I always write the full three-part HH:MM:SS.mmm in WebVTT to avoid compatibility issues with older parsers that expect it.

What is the difference between WebVTT and TTML or IMSC?

WebVTT is designed for web browsers and the HTML5 <track> element. TTML and its streaming profile IMSC1.1 are XML-based formats used for professional streaming delivery, particularly to platforms like Netflix that specify TTML or IMSC in their delivery requirements. For how each format fits in a delivery pipeline, see my notes on subtitle translation workflow.

Official Sources

Dao Huy (Lucas)
Dao Huy (Lucas)
Graduate, University of Foreign Language Studies, University of Da Nang. Signs a certificate of accuracy on every certified translation (USCIS, IRCC).

Written by Dao Huy (Lucas), Vietnamese translator and localization specialist (English, Chinese and French into Vietnamese). See translation services →

Get QuoteWhatsApp