A subtitle file format defines how a file stores what to show on screen and when: every cue pairs a start time and an end time with a piece of text (or, for disc formats, an image). The short answer to "which one should I use?" is SRT when you need it to play everywhere, WebVTT for video on the web, ASS when you need real styling, and TTML/IMSC when a streaming platform or broadcaster tells you to.
The rest of this guide shows what each format actually looks like, with copy-paste examples, the gotchas that break playback, and the commands to convert between them.
Subtitle File Formats at a Glance
| Format | Extension | Stored as | Styling | Use it for |
|---|---|---|---|---|
| SRT (SubRip) | .srt |
Plain text | Basic tags, unreliable | Maximum compatibility, offline video |
| WebVTT | .vtt |
Plain text | CSS via ::cue, cue positioning |
HTML5 <video> on the web |
| ASS / SSA | .ass, .ssa |
Plain text | Full: fonts, colors, positioning, effects | Styled subtitles, anime, karaoke |
| TTML / DFXP / IMSC | .ttml, .dfxp, .xml |
XML | Full | Streaming and broadcast delivery |
| SCC | .scc |
Hex-encoded CEA-608 | Limited | US broadcast closed captions |
| SBV | .sbv |
Plain text | None | YouTube uploads |
| MicroDVD | .sub |
Plain text, frame-based | None | Legacy video files |
| EBU-STL | .stl |
Binary | Limited | European broadcast archives |
| VobSub | .idx + .sub |
Images | Burned into the image | DVD rips |
| PGS | .sup |
Images | Burned into the image | Blu-ray rips |
How to Pick a Subtitle Format
- Embedding video on a website? Use WebVTT. It's the only format the HTML5
<track>element supports. - Shipping a video file people play in VLC, Plex, or on a TV? Use SRT. Every player reads it.
- Need custom fonts, colors, or text anywhere on screen? Use ASS, and accept that most web players won't render it.
- Delivering to a streaming service or broadcaster? Use whatever their spec asks for. That's usually a TTML profile such as IMSC, or SCC in the US.
- Stuck with
.sub,.idx, or.supfiles? Those are probably image-based, and you'll need OCR to get text out of them.
Whatever you pick, save text-based subtitle files as UTF-8. A file that looks fine on your machine turns into ’é gibberish on someone else's player when the encoding is wrong, and non-Latin scripts suffer the most. Our post on why you should use UTF-8 everywhere explains why.
Timestamp Formats Compared
Most conversion bugs come from timestamps. Here's the same moment, 1 minute 2.5 seconds, in each format:
| Format | Timestamp | Notes |
|---|---|---|
| SRT | 00:01:02,500 |
Comma before milliseconds, hours required |
| WebVTT | 01:02.500 or 00:01:02.500 |
Period before milliseconds, hours optional |
| ASS | 0:01:02.50 |
Single-digit hours, centiseconds |
| SBV | 0:01:02.500 |
Single-digit hours, period |
| TTML | 00:01:02.500 or 62.5s |
Clock time or offset, not both |
| SCC | 00:01:02:15 |
Frames instead of milliseconds (29.97 fps) |
| MicroDVD | {1499} |
Frame number, depends on the video's frame rate |
SRT (SubRip): The Universal Subtitle Format
SRT is the format every player understands, from VLC to smart TVs to YouTube. It has no official specification; the format is whatever the SubRip program wrote in the early 2000s, and everyone has copied it since. That's why it's so simple.
SRT File Structure
An SRT file is a list of numbered cues separated by blank lines. Each cue has:
- A counter, starting at
1. - A timecode line:
start --> end, formatted asHH:MM:SS,mmm. - One or more lines of text. Two lines is the practical maximum.
- A blank line that ends the cue.
Here's a complete SRT file example:
1
00:00:03,450 --> 00:00:05,250
This is the first subtitle.
2
00:00:06,000 --> 00:00:08,750
It can span
two lines.
SRT Formatting Tags and Positioning
Many players render a small set of HTML-like tags in SRT files:
3
00:00:09,000 --> 00:00:11,500
<i>Italic</i>, <b>bold</b>, and <font color="#ffff00">yellow</font> text.
4
00:00:12,000 --> 00:00:14,000
{\an8}This line is shown at the top of the screen.
The {\an8} tag is borrowed from ASS and moves a cue to the top-center, which you need when on-screen text sits at the bottom. Desktop players like VLC and mpv support it, but support elsewhere is patchy. Treat all SRT styling as a hint that some players will show as literal text.
SRT Rules That Prevent Most Playback Bugs
- Use a comma before the milliseconds.
00:00:03.450is WebVTT syntax, and strict SRT parsers reject it. - Keep cues from overlapping. Some players show both cues at once; others drop one.
- End every cue with a blank line, including the last one. A missing blank line merges two cues.
- Keep lines short. Netflix's English guideline is 42 characters per line and two lines per cue, which is a good default.
- Save as UTF-8. Only add a byte order mark (BOM) if an old player shows garbled accents without one.
WebVTT (.vtt): The Subtitle Format for Web Video
WebVTT (Web Video Text Tracks) is the W3C format for HTML5 video. If you're putting subtitles on a web page, this is the format to use: browsers support it natively through the <track> element, and they don't support SRT at all.
A WebVTT file looks like SRT with three differences: it starts with a WEBVTT header, it uses a period before the milliseconds, and cue numbers are optional.
WEBVTT
NOTE This is a comment. Players ignore it, so it's a good place for notes to translators.
intro
00:00:03.450 --> 00:00:05.250
This is a WebVTT subtitle.
00:00:06.000 --> 00:00:08.750
The cue identifier above ("intro") is optional.
Positioning and Styling WebVTT Cues
Cue settings go after the end timestamp on the timing line:
WEBVTT
00:00:10.500 --> 00:00:13.000 line:10% position:50% align:center
Placed near the top of the video, centered.
00:00:15.000 --> 00:00:18.000
You can style <c.highlight>part of a line</c.highlight> with a class.
00:00:18.500 --> 00:00:21.000
<v Maria>Voice spans mark who is speaking.
line sets the vertical position, position the horizontal one, and align accepts start, center, end, left, or right. (Older examples use align:middle, which was renamed to center.)
Classes like highlight are styled from your page's CSS with the ::cue pseudo-element:
video::cue {
background: rgb(0 0 0 / 70%);
font-family: system-ui, sans-serif;
}
video::cue(.highlight) {
color: #ffd700;
}
Adding WebVTT Subtitles to an HTML5 Video
<video controls src="/media/demo.mp4">
<track kind="subtitles" src="/media/demo.en.vtt" srclang="en" label="English" default>
<track kind="subtitles" src="/media/demo.nl.vtt" srclang="nl" label="Nederlands">
</video>
Two things trip people up here:
- Serve
.vttfiles astext/vtt. Some browsers ignore tracks with the wrong MIME type, and the failure is silent. - Cross-origin tracks need CORS. If the
.vttfile lives on a CDN on a different domain, addcrossorigin="anonymous"to the<video>element and send anAccess-Control-Allow-Originheader. Tracks also won't load when you open the HTML fromfile://.
ASS and SSA: Subtitles With Advanced Styling
ASS (Advanced SubStation Alpha) is the subtitle format with advanced styling capabilities: custom fonts, colors, outlines, shadows, rotation, animation, karaoke effects, and pixel-exact positioning. It's the successor to SSA (SubStation Alpha) and the standard in anime fansubbing, where subtitles often match on-screen signs.
ASS File Structure
An ASS file is plain text split into sections. [Script Info] holds metadata and the resolution the subtitles were positioned against, [V4+ Styles] defines named styles, and [Events] holds the actual cues.
[Script Info]
Title: My Video
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,60,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,1,2,10,10,10,1
Style: TopBanner,Impact,72,&H0000FFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,3,2,8,10,10,10,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:05.25,0:00:08.10,Default,,0,0,0,,A standard subtitle.\NThe \N starts a new line.
Dialogue: 0,0:00:10.50,0:00:15.00,TopBanner,,0,0,0,,Big yellow text at the top!
Dialogue: 0,0:00:16.00,0:00:18.00,Default,,0,0,0,,{\i1}Override tags{\i0} change style mid-line.
Two ASS gotchas:
- Colors are
&HAABBGGRR: alpha first, then blue, green, red, the reverse of CSS.&H0000FFFFis yellow, not cyan. An alpha of00is fully opaque. - Timestamps use centiseconds (
0:00:05.25), not milliseconds. Converting to SRT means multiplying the fraction by 10, which conversion tools do for you.
Playing ASS Subtitles on the Web
Browsers can't render ASS. Desktop players built on libass (VLC, mpv, MPC-HC) render it perfectly, and on the web you need a player that bundles libass compiled to WebAssembly, such as JASSUB. If you can't control the player, convert to WebVTT and accept that most of the styling is lost.
TTML, DFXP, and IMSC: XML Subtitle Formats
TTML (Timed Text Markup Language) is the W3C's XML subtitle format. You'll see it under several names:
- DFXP is the original name of TTML 1.0, and many tools still use the
.dfxpextension. - IMSC (Internet Media Subtitles and Captions) is a TTML profile: a subset that players can actually implement. Streaming services such as Netflix take IMSC deliveries.
A minimal, valid TTML file:
<?xml version="1.0" encoding="UTF-8"?>
<tt xmlns="http://www.w3.org/ns/ttml" xml:lang="en">
<body>
<div>
<p begin="00:00:03.450" end="00:00:05.250">This is a TTML subtitle.</p>
<p begin="00:00:06.000" end="00:00:08.750">It's structured with XML.</p>
</div>
</body>
</tt>
Times are either clock time (00:00:03.450) or an offset with a unit (3.45s). Mixing them, as in 00:00:03.450s, is invalid. Real delivery files add <head> sections with regions and styles, and each platform's spec lists what it accepts. You'll rarely write TTML by hand: generate it from SRT or WebVTT and validate it against the platform's profile.
EBU-STL: The Legacy Broadcast Format
EBU-STL (EBU Tech 3264, from 1991) is the binary exchange format European broadcasters used before TTML. A file is a 1,024-byte header block (GSI) followed by 128-byte blocks (TTI) for the subtitle text and timing. It was designed for floppy disks, and you'll mostly meet it in archive material. You can't open it in a text editor; Subtitle Edit reads and converts it.
SCC: The Closed Caption File Format
SCC (Scenarist Closed Caption) stores CEA-608 closed captions, the caption standard of US analog TV that's still used across US broadcast and by platforms that ingest broadcast content. Unlike other text formats, it doesn't store readable text. Each line holds a SMPTE timecode followed by pairs of hex bytes that are the raw CEA-608 commands and characters:
Scenarist_SCC V1.0
00:00:01:15 9420 9420 94ae 94ae 9452 9452 c8e5 ecec ef80 942f 942f
That line loads "Hello" into caption memory and displays it at 1 second and 15 frames. SCC is limited to the basic Latin character set, fixed caption positions, and 29.97 fps timing. Never edit SCC by hand: convert to and from it with a subtitle editor.
SBV and the Subtitle Formats YouTube Accepts
SBV is YouTube's own simple format. It has no counters, and the start and end times sit on one line separated by a comma:
0:00:03.450,0:00:05.250
This is the first subtitle.
0:00:06.000,0:00:08.750
It appears for a few seconds.
YouTube accepts SRT, SBV, WebVTT, TTML/DFXP, and SCC, among others, but not ASS. When you download captions from YouTube Studio, you can pick SRT, SBV, or VTT.
What Is a .sub File?
The .sub extension is used by three unrelated formats, which is why a .sub file sometimes opens fine and sometimes shows up as garbage. Open it in a text editor to find out which one you have:
MicroDVD is plain text with times as frame numbers in curly braces. A | breaks the line:
{1}{1}23.976
{83}{126}This is the first subtitle.
{144}{210}It appears for a few seconds.|Second line.
Because the timing is in frames, the file only lines up with a video at the same frame rate. Some players read the frame rate from a first cue like {1}{1}23.976. Converting MicroDVD to SRT fixes the timing for good.
SubViewer is plain text with readable timestamps like 00:00:03.45,00:00:05.25, and [br] for line breaks.
VobSub is the binary one. If the .sub file is unreadable and there's an .idx file with the same name next to it, it contains subtitle images from a DVD. See the image-based section below.
VobSub vs UTF-8 Subtitles
When you inspect an MKV file with a tool like MediaInfo or MKVToolNix, subtitle tracks often show up as VobSub or UTF-8. "UTF-8" here means a text subtitle track (Matroska's S_TEXT/UTF8 codec, which is SRT inside the container). VobSub means image subtitles ripped from a DVD. Pick the UTF-8 track when you want to edit, search, restyle, or translate the subtitles. Pick VobSub only when you need the disc's exact look.
Image-Based Subtitles: VobSub and PGS
DVDs and Blu-rays don't store subtitle text at all. They store a sequence of pictures of the text, each with a timestamp:
- VobSub (
.idx+.sub) comes from DVDs. The.idxfile is a small text index of timestamps and positions; the.subfile holds the bitmaps. - PGS (
.sup), short for Presentation Graphic Stream, is the higher-resolution Blu-ray equivalent, in one file.
Pre-rendered images look identical on every player, but they're large (often tens of megabytes, versus about 50–100 KB for an SRT of the same film), impossible to search, and impossible to fix or translate without first turning them back into text.
Converting Image Subtitles to SRT With OCR
To get text out of VobSub or PGS, you need OCR (optical character recognition). FFmpeg can't do this. If you try ffmpeg -i subs.sup subs.srt, it fails with "Subtitle encoding currently only possible from text to text or bitmap to bitmap".
Use Subtitle Edit instead: open the .sup or .idx file and it runs OCR (Tesseract or its own engine) and saves the result as SRT. Budget time for a manual pass afterward. OCR mixes up characters like l, I, and 1, and italic text is the most error-prone.
To pull an image track out of an MKV first, mkvextract from MKVToolNix copies it as-is:
# Track IDs come from `mkvmerge -i movie.mkv`
mkvextract movie.mkv tracks 3:subs.sup
Converting and Editing Subtitle Files
Converting Subtitle Formats With FFmpeg
FFmpeg converts between text-based formats in one command:
# SRT to WebVTT
ffmpeg -i input.srt output.vtt
# ASS to SRT (styling is dropped)
ffmpeg -i input.ass output.srt
# Extract the first text subtitle track from a video
ffmpeg -i movie.mkv -map 0:s:0 subs.srt
# Burn subtitles into the video permanently
ffmpeg -i video.mp4 -vf subtitles=subs.srt output.mp4
Working With Subtitles in Python
For scripting, pysubs2 reads and writes SRT, WebVTT, ASS, MicroDVD, and a few other formats:
import pysubs2
subs = pysubs2.load("input.srt", encoding="utf-8")
subs.shift(s=2.5) # everything 2.5 seconds later
subs.save("output.vtt") # the format follows the extension
Subtitle Editors
- Subtitle Edit (free, Windows, runs on Linux via Mono) handles more than 300 formats, OCR, waveform-based timing, and batch conversion. Start here.
- Aegisub (free, cross-platform) is the editor for ASS styling and typesetting.
Translating Subtitle Files
Translating subtitles has the same traps as translating app strings, plus a timing constraint:
- Translate text, not structure. Timestamps, cue numbers, tags like
<i>and{\an8}, and ASS\Nline breaks must come through untouched. With pysubs2, translate each event'splaintextand leave the rest alone. - Translate sentences, not cues. A sentence often runs across two or three cues. Translating each cue on its own produces broken grammar, so give the translator (human or AI) the surrounding cues as context.
- Watch the length. German and French text often runs 20–30% longer than English, but the cue is on screen for the same time. Long translations need re-splitting or shorter wording.
- Keep terms consistent. Character names and product terms should be translated the same way in every file, which is what a glossary is for.
If your video is part of a Django app, the text around it (player controls, track labels, language names) lives in your .po files and has the same problems: placeholders that must survive and terms that must stay consistent. TranslateBot automates that part with one command, preserving placeholders and following your glossary. For how .po files are structured, see our guide to gettext .po files.
Subtitle Format FAQ
What Is the Best Subtitle File Format?
For websites, WebVTT, because it's the only format browsers support natively. For video files that need to play anywhere, SRT. For styled subtitles in a player you control, ASS.
What's the Difference Between SRT and VTT?
WebVTT starts with a WEBVTT header, uses a period instead of a comma before the milliseconds, makes cue numbers optional, and supports positioning, CSS styling, comments, and speaker tags. Converting SRT to VTT keeps everything that matters; going the other way drops the styling and positioning.
Can I Put HTML Tags in an SRT File?
Yes, <i>, <b>, <u>, and <font color> work in many players, but not all. Some show the raw tags as text. If styling matters, use WebVTT on the web or ASS in desktop players.
How Do I Convert Between Subtitle Formats?
For text formats, ffmpeg -i input.srt output.vtt (change the extensions for other formats). For image formats like PGS and VobSub, use Subtitle Edit's OCR. For batch jobs in Python, use pysubs2.