Speech-to-text

Captions and subtitles: SRT, VTT, and timing

Turning transcripts into readable captions.

Updated 23 September 20265 min readBy the Reson8 research team

A transcript is not a set of captions. Captions break speech into short, timed blocks, called cues, that a viewer can read while watching, and they follow rules on line length, reading speed and where lines break. SRT and WebVTT are the two plain-text formats most tools accept. Building good captions from speech recognition output needs accurate word timestamps and a segmentation step that respects both the timing of speech and the limits of reading.

Key takeaways

  • SRT and WebVTT store the same thing: numbered or unnumbered cues with start and end times and one or two lines of text.
  • Good cues are short: typically at most two lines of around 37 to 42 characters, on screen for roughly one to seven seconds.
  • Reading speed is the main constraint. Style guides cap it at around 15 to 20 characters per second for adult viewers.
  • Break lines and cues at linguistic boundaries, not mid-phrase. A cue should end where a phrase ends.
  • Captions for accessibility include speaker changes and non-speech sounds, not just words.

Captions and subtitles#

In North American usage, captions are same-language text for viewers who cannot hear the audio, and include non-speech information such as [door slams] or [music]; subtitles are translations for viewers who can hear but do not understand the language. In the UK and much of Europe, "subtitles" covers both, with SDH (subtitles for the deaf and hard of hearing) used for the accessibility variant. The file formats are the same. This article uses both words interchangeably except where the distinction matters.

Captions are also a legal requirement in many settings. The Web Content Accessibility Guidelines require captions for prerecorded video at level A and for live video at level AA, and the European Accessibility Act, applicable from June 2025, extends accessibility requirements to many audiovisual services sold in the EU.

SRT and WebVTT#

SRT, from the SubRip program, is the most widely supported format. Each cue is a sequence number, a timing line, one or more text lines and a blank line. Milliseconds are separated by a comma.

1
00:00:01,200 --> 00:00:03,850
Welcome back to the programme.

2
00:00:04,100 --> 00:00:07,300
Today we're looking at how
speech becomes captions.

WebVTT is the W3C format for HTML <track> elements. It starts with a WEBVTT header, uses a dot before milliseconds, makes cue numbers optional, and adds cue settings for position and alignment, voice tags for speakers, and optional styling.

WEBVTT

00:00:01.200 --> 00:00:03.850
<v Presenter>Welcome back to the programme.

00:00:04.100 --> 00:00:07.300 line:85%
<v Presenter>Today we're looking at how
speech becomes captions.
FormatWhere it is usedTimingStyling and position
SRTAlmost everywhere: editors, players, platformsHH:MM:SS,mmmNone in the spec; some players read basic tags
WebVTTHTML5 video, streaming playersHH:MM:SS.mmmCue settings, voice tags, CSS
TTML / EBU-TTBroadcast and archive workflowsSeveral time basesFull XML styling and layout

From transcript to cues#

Words with timestamps Cue segmentation pauses, sentences Line breaking 2 lines, 42 chars SRT / VTT from ASR or forced alignment 1–7 s per cue split at speaker change ≤ ~17–20 CPS break between phrases gap ≥ 2 frames between cues Each step enforces reading constraints on top of what the audio timing allows.
Captioning is a constrained segmentation problem. Word timing says where text can go; reading speed and line length say how much of it fits.

Timing#

Accurate word timestamps are the foundation. Captions that appear before the words are spoken, or linger after, feel wrong even when the text is perfect. For prerecorded media, forced alignment of the final transcript against the audio usually gives better timing than the recogniser's own timestamps. For live captions, timestamps come from the streaming recogniser and the captioner has to accept some delay.

Cue length and reading speed#

Professional style guides converge on similar limits. Netflix's English guide allows at most 42 characters per line and two lines per cue, a minimum duration of five-sixths of a second and a maximum of seven seconds, and a reading speed of up to 20 characters per second for adult content. The BBC's guidelines express reading speed in words per minute, with around 160 to 180 as the normal rate. Children's content is slower in both. Speech is often faster than comfortable reading, so verbatim captions for fast talkers may need to be condensed, which is an editorial decision beyond what recognition can make.

Where to break#

Line and cue breaks should follow grammar. Keep an article with its noun, a preposition with its object, a first name with a surname. Prefer breaking after punctuation or before conjunctions. Compare:

We will meet the new head of
the department on Monday.

We will meet the new head
of the department on Monday.

The first splits "head of" from its object; the second breaks at a phrase boundary. Balanced lines of similar length are easier to read than a long line above a single word.

Generating captions programmatically#

A basic segmenter walks the word list and closes a cue when adding the next word would exceed the character or duration limit, or when there is a long pause, a sentence end or a speaker change.

def to_srt_time(t):
    ms = round(t * 1000)
    h, ms = divmod(ms, 3_600_000)
    m, ms = divmod(ms, 60_000)
    s, ms = divmod(ms, 1000)
    return f"{h:02}:{m:02}:{s:02},{ms:03}"

def build_cues(words, max_chars=84, max_dur=7.0, pause=0.6):
    cues, current = [], []
    for w in words:
        if current:
            text = " ".join(x["word"] for x in current + [w])
            too_long = len(text) > max_chars or w["end"] - current[0]["start"] > max_dur
            gap = w["start"] - current[-1]["end"] > pause
            sentence_end = current[-1]["word"].endswith((".", "?", "!"))
            if too_long or gap or sentence_end:
                cues.append(current)
                current = []
        current.append(w)
    if current:
        cues.append(current)
    return cues

def write_srt(cues):
    blocks = []
    for i, cue in enumerate(cues, 1):
        text = " ".join(w["word"] for w in cue)
        blocks.append(f"{i}\n{to_srt_time(cue[0]['start'])} --> "
                      f"{to_srt_time(cue[-1]['end'])}\n{text}\n")
    return "\n".join(blocks)

This produces usable cues but leaves line breaking, minimum duration and reading-speed checks to a second pass. Production tools also extend very short cues into available silence, and enforce a small gap so consecutive cues do not visually merge.

Live captions#

Live captioning uses the partial results of a streaming recogniser, which change as more audio arrives. Showing every revision makes text jump; waiting for finals adds delay. Broadcast systems often use roll-up captions, where text scrolls line by line and only settled words are appended, rather than the pop-on blocks used for prerecorded content. A common compromise is to display partials but only commit text to the caption once it has been stable for a short time.

Common questions#

Should I use SRT or WebVTT?

WebVTT for web players using HTML5 video, since browsers support it natively. SRT for maximum compatibility with editing tools and platforms. Converting between them is trivial for plain cues.

Why do my auto-generated captions feel out of sync?

Usually coarse timestamps, cues that start at the beginning of a segment rather than the first word, or a fixed offset introduced by trimming or re-encoding the video. Forced alignment of the final text fixes the first two.

Do captions need to be verbatim?

Accessibility guidance generally favours closeness to the speech, but reading-speed limits sometimes force light editing. Filler words and false starts are commonly removed.

How should speakers be shown?

By a label, a leading dash, colour or on-screen position, depending on the style guide. WebVTT has voice tags for this; SRT has no standard mechanism.

References#

  1. W3C. WebVTT: The Web Video Text Tracks Format. w3.org.
  2. W3C (2018). Web Content Accessibility Guidelines (WCAG) 2.1, success criteria 1.2.2 and 1.2.4. w3.org.
  3. Directive (EU) 2019/882 on the accessibility requirements for products and services (European Accessibility Act). EUR-Lex.
  4. BBC Subtitle Guidelines. bbc.co.uk.
  5. Netflix. English (USA) Timed Text Style Guide. Netflix Partner Help Center.
  6. EBU Tech 3350. EBU-TT Part 1: Subtitling format definition. European Broadcasting Union.

Try Reson8 on your own audio

Speech recognition for European languages that adapts to your vocabulary from text, in under a minute. Free tier, EU-only processing.