A WebVTT file is UTF-8 text, defined by the W3C’s WebVTT specification. It is a header
followed by blocks, with blank lines between them. Its media type is
text/vtt and its extension .vtt.
Header
| Part | Bytes or text | Notes |
|---|---|---|
| Byte order mark | EF BB BF | Optional. |
| Signature | WEBVTT (57 45 42 56 54 54) | Required. Must be followed by a space, a tab, a line ending or the end of the file, so WEBVTTX is not a WebVTT file. |
| Header text | a space or tab, then any text | Optional, on the same line, such as WEBVTT - Episode 1. Players ignore it. |
| Blank line | two or more line endings | Ends the header. |
A line ending is CR LF, LF or CR. The text is always UTF-8; there is no way to declare another encoding.
Blocks
Blocks are separated by one or more blank lines, and no block may contain a blank line. They come in this order:
REGION,STYLEandNOTEblocks, in any order;- then cue and
NOTEblocks.
Once the first cue has appeared, a STYLE or REGION block is
no longer recognised. A block that is none of these is ignored.
| Block | First line | Then | Meaning |
|---|---|---|---|
| Cue | an optional identifier, or the timing line | the timing line, then the text | Text shown for a time. See Cues and settings. |
| Comment | NOTE, then a space, a tab or a line ending, and any text | more comment lines | Ignored by players. |
| Style | STYLE, optionally followed by spaces or tabs | a CSS style sheet | Styles for the cues. See Styling with CSS. |
| Region | REGION, optionally followed by spaces or tabs | region settings | A named area of the screen. See Regions. |
The three characters --> may not appear anywhere in a comment, style
sheet, identifier or cue text, because a parser takes any line containing them as a
timing line.
Kinds of file
Every cue in one file holds the same kind of data. The file does not say which; the
web page does, with the kind of its <track>
element.
| Kind | Cue text | Rule |
|---|---|---|
| Subtitles or captions | Text with tags and character references | Cues may overlap freely. |
| Chapters | A plain title: text and character references, no tags | Cues must nest: any two either do not overlap, or one lies wholly inside the other. |
| Metadata | Any text with no blank line, such as JSON, for scripts to read | None. |
Timestamp map in HLS
HLS (M3U8) cuts WebVTT into segments to run beside MPEG-2 transport stream video, and RFC 8216 adds one header line so that cue times can be matched to the video’s clock:
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000
00:00:01.000 --> 00:00:03.500
Where are we going?
MPEGTS is a 90 kHz presentation timestamp, here 10 seconds,
that corresponds to the cue time LOCAL. So this cue shows at 11 s on the
video’s clock. The line goes directly after WEBVTT, before the blank
line that ends the header.Worked example
WEBVTT - Episode 1
REGION
id:speaker
width:40%
lines:3
regionanchor:0%,100%
viewportanchor:10%,90%
scroll:up
STYLE
::cue(.loud) { font-weight: bold; }
NOTE Dialogue starts here
intro-1
00:01.000 --> 00:03.500 region:speaker
<v Anna>Where are we going?
00:04.000 --> 00:06.250 line:0 align:start
<v.loud Ben>Somewhere we have never been!