VTT to SRT Converter
- SubRip has no published specification and no registered media type. This converter matches the shape every player follows rather than implementing a standard, so the SubRip half of every rule here is convention.
- The WEBVTT header line was removed. FMT-subrip-header: a SubRip file has no header line.
Going the other way? Convert SRT back to VTT →
How do you convert VTT to SRT?
VTT to SRT drops the header and the cue settings, numbers the cues from 1, and turns the full stop before the thousandths back into a comma.
- Paste the WebVTT file above. It has to open with the string WEBVTT, followed by a blank line.
- Drop the header line and any NOTE, STYLE or REGION block, because a SubRip file has nowhere to put them.
- Number the cues from 1 in the order they appear, replacing any cue identifier that is not already that number.
- Turn the full stop before the thousandths back into a comma in both timestamps, and write the hours field on every cue.
This page writes the header and cue settings removed, cues numbered from 1 in order, and the full stop swapped back to a comma in both timestamps.
VTT to SRT Conversion Table
The same six parts as the other direction, read from the WebVTT side. The timestamp difference between the two subtitle formats is one character: SubRip writes a comma before the milliseconds and WebVTT writes a full stop. 00:00:01,500 in SubRip is 00:00:01.500 in WebVTT.
| WebVTT part | SubRip part | What changes |
|---|---|---|
| a WEBVTT header line | none | the header line is removed |
| optional; where present it must be unique across the file | a sequential index number on every cue, counted from 1 | a non-numeric identifier is replaced |
| [HH:]MM:SS.mmm | HH:MM:SS,mmm | the full stop becomes a comma |
| optional; required only when the hours are not zero, and then two or more digits | always written | the hours field is added where it was left out |
| cue settings after the end timestamp | none | the settings are dropped |
| a NOTE block | none | the block is dropped |
A format is defined by what it can say. The rows below put the two halves of this conversion side by side, so the gap the conversion has to cross is a thing you can read rather than a thing you find out later. Every value in the table is the wording the defining document uses, not a summary of it, and a dash means the format has no answer to that row at all.
| What it says | WebVTT | SubRip |
|---|---|---|
| Specification | W3C WebVTT: The Web Video Text Tracks Format, Candidate Recommendation Draft, 20 May 2026 | none published - the format is defined by the behaviour of the SubRip program and by convention |
| Media type | text/vtt | none registered |
| Structure | a WEBVTT header line, then region, style, comment and cue blocks separated by line terminators | cue blocks of an index line, a timing line, one or more text lines and a blank line |
| Header line | — | none |
| Timestamp | [HH:]MM:SS.mmm | HH:MM:SS,mmm |
| Fraction mark | U+002E FULL STOP | a comma |
| Hours field | optional; required only when the hours are not zero, and then two or more digits | — |
| Timing line | the string --> surrounded by one or more spaces or tabs | — |
| Cue identifier | optional; where present it must be unique across the file | a sequential index number on every cue, counted from 1 |
| Line terminator | CRLF, LF or CR | — |
| Comment | a NOTE block | none |
| Encoding | UTF-8 | none - the format carries no encoding declaration |
Worked Example: VTT to SRT
One cue, converted here at build time by the same code the box above runs. The working under it shows the timing line that went in, the decision taken, and the numbered cue that came out.
WEBVTT
00:00:01.500 --> 00:00:04.000
Hello
1
00:00:01,500 --> 00:00:04,000
Hello
Result: the WebVTT above is the SubRip beside it, and every decision that made it is listed below.
The payload came through untouched, which is what makes this pair a punctuation change rather than a mapping. WebVTT was built on SubRip. The W3C specification's acknowledgements name the SubRip program's SRT file format as the basis for the WebVTT text track format, which is why the two convert into each other so cleanly.
Subtitle files are timed text, not structured data. SubRip and WebVTT carry lines of prose against timestamps; they have no fields, no keys and no nesting, which is why they convert into each other and not into JSON. There is no field, no key and no type to carry across, so what is left is a header line, a number and a comma.
The one thing to watch after the conversion is how you save the file. A WebVTT file must be encoded as UTF-8 and labelled text/vtt. A SubRip file declares no encoding at all, which is why accented characters in an SRT file can arrive as the wrong characters.
Check it in reverse
Going back adds the header line and turns the comma into a full stop again, and for a file of plain cues that returns what you started from. What it cannot return is anything SubRip had nowhere to keep: the cue settings, the styling, the comment blocks, and a cue identifier that was a word rather than a number. Those are gone at this step, not the next one.
To prove nothing was lost, convert the SRT result back to VTT and compare it with the file you started from.
What This Conversion Cannot Carry
WebVTT carries more than SubRip does, so this is the lossier of the two directions and the converter names every part it dropped. A WebVTT timestamp is two-digit minutes, two-digit seconds, a full stop and three digits of thousandths, with the hours field optional and required only when the hours are not zero. Both 01:30.000 and 00:01:30.000 are valid WebVTT.
- The SubRip side of every rule here
- SubRip has no published specification and no registered media type. This converter matches the shape every player follows rather than implementing a standard, so the SubRip half of every rule here is convention.
- The WEBVTT header line
- The WEBVTT header line was removed. FMT-subrip-header: a SubRip file has no header line.
- A NOTE block
- A NOTE block was dropped. FMT-webvtt-comment gives WebVTT a comment block; FMT-subrip-comment gives SubRip none.
- Cue settings
- Cue settings ("align:start") were dropped. WebVTT writes position, alignment and size after the end timestamp and SubRip has nowhere to put them.
- A cue identifier that is not a number
- The WebVTT cue identifier "intro" was replaced by the sequential number 1. FMT-subrip-cue-identifier: the SubRip convention is a sequential index number on every cue, counted from 1, so a non-numeric identifier cannot survive.
- A cue span such as a voice tag
- A WebVTT cue span such as <v Speaker> was left in the payload unchanged. SubRip has no equivalent, so a player that does not know the tag will show it as text.
- A STYLE or REGION block
- A STYLE block was dropped. WebVTT carries styling and region definitions and SubRip carries neither.
- A byte order mark
- A byte order mark stood at the front of the file. It was removed rather than read as part of the header line.
Each line above is written by the converter itself, and it appears under your own result whenever your document raises it. Nothing is dropped without one.
The sample above reverses exactly - read the same cues back in as WebVTT .
What Does SubRip Not Carry?
Where the cue numbers come from
From the position of the cue, not from the file. WebVTT cue identifiers are optional, and where they appear the specification requires each one to be unique. SubRip numbers its cues in order by convention, so a VTT to SRT conversion adds the numbers and an SRT to VTT conversion can drop them.
What happens when the hours are left out
They are written in, because SubRip requires them. A SubRip timestamp is written HH:MM:SS,mmm - two digits each for hours, minutes and seconds, then a comma and three digits of milliseconds. SubRip has no published specification and no registered media type, so this is the shape every player follows rather than a rule anyone wrote down.
What SubRip has no place for
The header line, the cue settings, the styling and the comments. Every WebVTT file opens with the string WEBVTT, and the W3C specification requires two or more line terminators between that line and the rest of the file. A SubRip file has no header line, so converting to WebVTT means adding one.
VTT to SRT in Code
The same conversion in two lines, one per language. Both strip the header and renumber; neither drops the cue settings for you. Neither line reports what the conversion could not carry; the converter above does.
Python: open("out.srt","w").write(re.sub(r"(\d\d:\d\d:\d\d)\.", r"\1,", body)) JavaScript: body.replace(/(\d\d:\d\d:\d\d)\.(\d\d\d)/g, "$1,$2") Common Mistakes
- Leaving the WEBVTT line at the top. A SubRip file has no header, so a player reading the result treats the first cue as malformed.
- Keeping a timestamp with no hours field. WebVTT lets the hours be left out and SubRip does not, so the field has to be written in.
- Expecting a voice tag or a styling span to render. SubRip has no equivalent, so a player that does not know the tag shows it as text.
Frequently Asked Questions
Is VTT the same as SRT?
No. They carry the same cues and differ in one timestamp character, a header line, and everything WebVTT adds on top: cue settings, styling, regions and comments.
Is converting VTT to SRT free?
Yes, and the file stays in your browser. The conversion runs on this page, so nothing is uploaded and nothing is stored.
What happens to WebVTT cue settings and styling?
They are dropped, and the converter lists each one it dropped. SubRip has nowhere to put position, alignment or size, and no styling of its own at all.
What happens when the VTT timestamp has no hours field?
The hours are written in as 00. WebVTT makes the field optional and SubRip does not, so a timestamp of 01:30.000 becomes 00:01:30,000.
Where do the SRT cue numbers come from?
From the position of each cue in the file, counted from 1. A WebVTT identifier that is already that number survives; anything else is replaced and reported.
Yes. The same file converts straight back in the SRT to VTT direction .
Related Conversions
The rest of the family sits on the subtitle and data format index.