Short answer: use WebVTT if the video plays in a browser, and SubRip if it plays anywhere else. HTML5’s <track> element accepts only VTT, and almost every other player on earth accepts SRT.
The two formats are close relatives — VTT was designed as a web-native evolution of SRT and kept its shape — so the conversion is trivial and the choice is rarely irreversible. What follows is what actually differs, and when the difference matters.
SubRip (.srt)
The oldest and most widely supported subtitle format, and about as simple as a file format gets: a numbered list of cues, each with a start time, an end time, and one or more lines of text.
1
00:00:00,580 --> 00:00:04,270
In the last video, we showed
that if you had a line, which
2
00:00:04,270 --> 00:00:09,020
we'll call a directrix--
we draw the directrix.
- Sequence numbers, starting at 1
- Timecodes as
HH:MM:SS,mmm --> HH:MM:SS,mmm— note the comma before milliseconds - Text on the following lines, which may wrap
- A blank line between entries
There is no official specification. SRT is defined by what SubRip wrote and what every player since has agreed to accept, which is why the tolerated variations — inline <i> and <b> tags, occasional positioning coordinates, missing sequence numbers — vary by player.
WebVTT (.vtt)
A W3C format built for HTML5 video. Same cue-list idea, with a header and a real specification behind it.
WEBVTT
STYLE
::cue {
background-color: transparent;
color: white;
}
NOTE Keep this under two lines for the mobile player
intro
00:00:00.000 --> 00:00:04.000 position:50% align:center
Welcome to this video tutorial
00:00:04.000 --> 00:00:08.500 line:90%
In this section, we'll explore
the key concepts you need to know
- A mandatory
WEBVTTfirst line - Timecodes with a dot before milliseconds
- Optional cue identifiers (
introabove) instead of, or as well as, sequence numbers - Cue settings after the timecode for position, alignment and line placement
STYLEblocks carrying CSS that applies through the::cuepseudo-elementREGIONblocks defining scrollable areas, used for roll-up captionsNOTEblocks — comments that never render
The differences that matter
SubRip .srt |
WebVTT .vtt |
|
|---|---|---|
| Specification | de facto | W3C standard |
| Header line | none | WEBVTT required |
| Millisecond separator | comma , |
dot . |
| Cue identifiers | sequence numbers | optional named identifiers |
HTML5 <track> |
✗ | ✓ |
| Styling | ad-hoc <i>/<b> by convention |
CSS via STYLE and ::cue |
| Positioning | ✗ (non-standard extensions only) | cue settings: position, line, align, size |
| Regions / roll-up | ✗ | ✓ |
| Comments | ✗ | NOTE blocks |
| Chapters and metadata tracks | ✗ | ✓ |
| Encoding | unspecified, in practice a mess | UTF-8 required |
| Player support | near-universal | browsers, and most modern players |
Two rows carry most of the practical weight.
Encoding. SRT has no declared encoding, so files arrive in Windows-1252, Latin-1, Shift-JIS or UTF-8 with no way to tell except guessing. This is the origin of the mojibake you have seen in downloaded subtitles. WebVTT mandates UTF-8, and that single constraint removes an entire category of problem from a localization pipeline.
Comments. NOTE blocks are the only place in either format to leave an instruction for a translator — this is a brand name, do not translate, or keep under 40 characters, it overlaps the lower third. SRT has nowhere to put that, so the guidance ends up in an email and then nowhere.
Converting SRT to VTT
Two mechanical edits:
- Prepend
WEBVTTand a blank line. - Replace the comma before milliseconds with a dot, in timecode lines only.
Sequence numbers can stay — VTT reads them as cue identifiers.
# Prepend the header, then fix the timecode separator
{ printf 'WEBVTT\n\n'; sed -E 's/([0-9]{2}:[0-9]{2}:[0-9]{2}),([0-9]{3})/\1.\2/g' input.srt; } > output.vtt
Going the other way is lossier, because everything VTT adds has to be dropped: styles, regions, cue settings and NOTE blocks have no SRT equivalent. Convert VTT → SRT only when a player forces you to, and keep the VTT as the source of truth.
What goes wrong in practice
Neither format has much surface area, so the failure modes are few and repetitive.
Byte order marks. An SRT saved from Notepad or exported by some Windows tooling starts with a UTF-8 BOM. Many players treat the BOM as part of the first cue’s sequence number, and cue 1 silently never displays. In VTT the same BOM breaks the WEBVTT header check and the whole file is rejected.
Overlapping and out-of-order cues. Both formats assume cues are in ascending time order and, in most players, non-overlapping. Editing tools that let you drag cues around will happily produce a file where cue 12 starts before cue 11 ends. Players disagree about what to do — some show both, some drop one, some stop rendering entirely.
Line endings. SRT’s entry separator is a blank line, so a file with mixed \r\n and \n endings can produce a “blank” line that is not blank. This is the classic symptom of a file that has been through a Windows editor and a Unix pipeline.
The --> arrow. It is exactly two hyphens and a greater-than sign, with a space on each side. A smart-quotes-style editor that converts the double hyphen into an em dash produces a file no parser will read, and the damage is invisible in a proportional font.
Timecode digits. SRT wants two-digit hours (00:01:02,500); VTT permits the hour to be omitted entirely (01:02.500). A converter that assumes one convention on input from the other will produce cues an hour out.
Most of these are worth catching with a parse step in CI rather than in review, because every one of them looks fine to a human reading the file.
Which to choose
Choose WebVTT if the video plays in a browser (it is the only option), you need captions positioned away from the default lower centre, you want CSS control over appearance, you are shipping chapters or metadata cues, or you want to carry translator instructions in the file itself.
Choose SubRip if you are targeting hardware players, older desktop players, or platforms that only accept SRT uploads; if you need the broadest possible compatibility with the least possible thought; or if the subtitles are an interchange artefact between tools rather than a delivery format.
Choose neither if you are delivering to broadcast or a major streaming platform. That world runs on TTML/DFXP, which is XML-based and carries the styling and timing metadata those workflows require.
In practice many teams keep an SRT master because it is the easiest thing to edit and review, and generate VTT at build time for the web player. That is a reasonable pipeline as long as the direction is one-way.
Translating either one
The text in both formats is plain, unescaped and unstructured, which makes them easy to translate and easy to break. Three things to watch:
Timings do not move. A translated cue has to fit the original time window. German and Finnish routinely run 20–30% longer than English; the translator needs to compress rather than translate literally, and needs to know that up front. This is a briefing problem, not a tooling one.
Line breaks are content. A two-line cue that becomes three lines will overflow the safe area on some players. Where the break falls also affects readability — breaking at a phrase boundary reads far better than breaking at the width limit.
Reading speed is a constraint. Roughly 15–20 characters per second is the usual comfortable ceiling for adult viewers. A cue on screen for two seconds has room for about 35 characters, whatever the translator would prefer to say.
WebTranslateIt reads and writes both formats, exposing only the subtitle text as translatable segments while timecodes, cue identifiers, styles and regions round-trip untouched. VTT NOTE blocks are carried through as developer comments, so a note written for the translator reaches them in the editor instead of being lost in the file. On the SRT side, the character counter and character limits are the practical tool for the reading-speed constraint: set a per-segment limit and the editor enforces it while the translator types.
Frequently asked questions
- What is the difference between SRT and VTT?
- WebVTT is a superset of SubRip in practice. Both are plain-text cue lists with timecodes, but VTT starts with a WEBVTT header, uses a dot before milliseconds instead of a comma, and adds styling, positioning, regions, comments, chapters and metadata. SRT has none of those and is correspondingly universal.
- Can I just rename a .srt file to .vtt?
- No. Renaming does not add the required WEBVTT header line, and the millisecond separator is still a comma, which a strict VTT parser rejects. The conversion is two mechanical edits — prepend WEBVTT and a blank line, and change the comma before milliseconds to a dot — but it does have to be done.
- Does HTML5 video support SRT?
- No. The <track> element requires WebVTT. Browsers will not render an SRT file passed to it. This is the single most common reason teams convert, and it is why any web video pipeline ends up producing VTT even when the source is SRT.
- Which format is better for translation?
- Both translate equally well because the text is plain in each. VTT is slightly better in practice because its NOTE blocks can carry instructions to the translator, which SRT has no way to express. What matters more than the format is that the tool preserves timings and cue identity while only exposing the text.
Keep reading
-
Subtitle file formats compared: SRT, VTT, TTML, ASS, SAMI and more
Eight subtitle formats side by side — what each one looks like, what it can express, where it is used, and which to choose for web, broadcast, anime or archive.
-
Placeholder formats cheat sheet: %s, %@, %{name}, {{name}}, {0}
Every string placeholder syntax you will meet, which language or framework uses it, and what breaks when a translator retypes one by hand.
-
Translate WebVTT .vtt files (documentation)
How WebTranslateIt parses VTT cues, styles, regions and NOTE comments.
Translate your app without the spreadsheet round-trip
WebTranslateIt reads the file formats and placeholder syntax described on this page, validates them as translators work, and syncs the results straight back into your repository.