# WebVTT

Canonical URL: https://encode.wiki/codecs/subtitles/webvtt/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): f228c6a124941e56f88b08f1535886d0bfb2ce799b5263406075143809a98226

WebVTT (Web Video Text Tracks, `.vtt`) is the subtitle and caption format of the web. It is derived from [SRT](/codecs/subtitles/srt/), adds positioning and CSS styling, and is what browsers expect in a `<track>` element, what HLS uses for subtitle segments, and the only text format [WebM](/containers/webm/) allows.

## Format

```text
WEBVTT

00:01.000 --> 00:04.000
- Never drink liquid nitrogen.

intro
00:05.000 --> 00:09.000 line:10% align:start
- It will perforate your <i>stomach</i>.
- You could die.
```

- The file starts with `WEBVTT`, then a blank line. UTF-8 only.
- Timestamps are `mm:ss.mmm` or `hh:mm:ss.mmm` with a **period**; SRT uses a comma.
- A cue may have an identifier line (`intro` above) and settings after the time range: `line`, `position`, `size`, `align`, `vertical`, `region`.
- Cue text accepts `<b>`, `<i>`, `<u>`, `<c.classname>` (for CSS), `<v Speaker>` (voice) and `<lang>`, plus inline timestamps for karaoke-style reveals.
- `NOTE` blocks are comments. `STYLE` blocks hold CSS targeting `::cue`, and `REGION` blocks define scrolling caption areas.

Browsers support only a subset of styling; `::cue` allows colour, font, background and similar properties, not arbitrary layout. For fine typography use [ASS](/codecs/subtitles/ssa/) in a player that supports it, or burn the subtitles in.

## Use it in a web page

```html
<video controls src="video.mp4">
  <track kind="subtitles" src="en.vtt" srclang="en" label="English" default />
  <track kind="captions" src="en-sdh.vtt" srclang="en" label="English (SDH)" />
</video>
```

`kind` is `subtitles` (translation), `captions` (dialogue plus sound descriptions, for deaf and hard-of-hearing viewers), `descriptions`, `chapters` or `metadata`. Serve `.vtt` files as `text/vtt`. If they live on another origin, the server must send CORS headers and the `<video>` needs a matching `crossorigin` attribute, otherwise the track silently fails to load. Tracks may also fail to load from `file://` pages, so test through a local web server.

## Convert and mux

```sh
ffmpeg -i subs.srt subs.vtt
ffmpeg -i subs.vtt subs.srt
ffmpeg -i video.mkv -map 0:s:0 subs.vtt
```

SRT to WebVTT is lossless for text, italics and bold. ASS to WebVTT keeps italics and bold but drops positioning and every other style. WebVTT to SRT drops cue settings and CSS.

Put WebVTT into WebM or MKV as a soft track:

```sh
ffmpeg -i video.webm -i subs.vtt -map 0 -map 1 -c copy -c:s webvtt output.webm
```

[MP4](/containers/mp4/) does not take WebVTT through FFmpeg; its text track is `mov_text`. Browsers do not reliably expose subtitle tracks embedded in a WebM or MP4, so the dependable pattern is a separate `.vtt` next to the video or listed in the HLS/DASH manifest.

## Streaming

HLS delivers subtitles as WebVTT segments referenced from the multivariant (master) playlist as a `SUBTITLES` rendition. DASH can use WebVTT or TTML/IMSC. Each HLS WebVTT segment should carry an `X-TIMESTAMP-MAP=LOCAL:…,MPEGTS:…` header mapping cue times to the video's MPEG-TS timestamps; without it, players must assume cue time 0 is MPEG-TS time 0. FFmpeg's `hls` muxer does not write the header and by default starts its MPEG-TS segments 1.4 s late, so its subtitles show up early in players that follow the spec. `-muxdelay 0` removes that offset.
