Skip to content

Media quality guide

Transcript Speaker and Timestamp Alignment Review: Keep Cue Structure Separate from Attribution

Review WebVTT cue order, duration, speaker tokens, overlap policy, and alignment to approved reference anchors.

A transcript can contain well-formed timestamps and still have an unapproved speaker label, a gap that the track contract does not explain, or an overlap that is intentional for a multi-speaker track. Start with the WebVTT structure, then compare bounded cue intervals and speaker tokens with an approved reference. This guide is not a transcript validator or upload service. It describes a structural alignment method, not a claim that a transcript is accurate, complete, accessible, or correctly attributed.

Updated

On this page

Treat WebVTT timing as a contract

The source dates shown in this guide identify documentation checks on 22 October 2026, not original publication dates. Follow the citation for the WebVTT specification being discussed.

The World Wide Web Consortium, (opens in a new tab) specification describes a WebVTT file body as UTF-8 text with the text/vtt MIME type. A cue has a start timestamp, a separator made of two hyphens followed by a greater-than sign, and an end timestamp. The start must be at least the start offsets of previous cues, and the end must be later than the cue start. Cue identifiers cannot contain a line break or that separator. The companion World Wide Web Consortium, (opens in a new tab) material is a separate presentation reference, not an identity or accuracy test.

The specification permits overlapping cues in general. A local transcript contract may forbid overlap for a single-speaker caption track, while a multi-speaker or metadata track may intentionally use nested or overlapping cues. Record track purpose before classifying overlap as a failure. Keep cue syntax, speaker annotation, and content accuracy as separate review dimensions.

Treat WebVTT timing as a contract (table)
DimensionRecordDo not infer
Text encodingUTF-8 contract and parser resultThat readable output proves every byte was valid
Cue orderCue identifier, start, end, and sequenceThat file order is business or speaker order
DurationEnd minus start and duration policyThat a short cue is missing speech
Speaker tokenSynthetic or approved category codeThat a voice label proves identity
AlignmentAnchor type and toleranceThat a timing match validates words
OverlapTrack purpose and local policyThat every overlap is invalid

Create a synthetic cue and anchor fixture

Use labels that cannot be confused with a real person and keep transcript text short. Pair a synthetic WebVTT fixture with an approved reference-anchor worksheet, not a copied recording. Name whether the anchor came from a synthetic generator, a manual approval, or another controlled annotation.

Synthetic WebVTT cues

Create a synthetic cue and anchor fixture code example, Plain text
WEBVTT

cue-001
00:00:00.000 --> 00:00:01.800
<v SPEAKER_A>synthetic greeting</v>

cue-002
00:00:01.900 --> 00:00:03.400
<v SPEAKER_B>synthetic response</v>

Synthetic approved anchors

Create a synthetic cue and anchor fixture code example, JSON
[
  {"speaker": "SPEAKER_A", "start": 0.000, "end": 1.800},
  {"speaker": "SPEAKER_B", "start": 1.900, "end": 3.400}
]

The values and labels are invented. If no approved anchor exists, the result is UNVERIFIED, not a failed transcript. A voice span carrying the token SPEAKER_A records an annotation; it does not prove that a diarization process identified a person or that the text is accurate. Keep real names and raw speech out of a public diagnostic.

Check timestamps and speaker tokens with bounded arithmetic

A local tolerance is an input, not a WebVTT rule. Choose it from the recording and annotation process, and record the decision. A bounded comparison can retain cue indexes and stable classes without copying cue text, voice names, or media paths.

Bounded cue and anchor comparison

Check timestamps and speaker tokens with bounded arithmetic code example, Python
import re

TIMESTAMP = re.compile(r"^(?:(\d+):)?(\d{2}):(\d{2})\.(\d{3})$")

def seconds(value):
    match = TIMESTAMP.fullmatch(value)
    if not match: raise ValueError("invalid_timestamp")
    hours = int(match.group(1) or 0)
    minutes, seconds_part = int(match.group(2)), int(match.group(3))
    millis = int(match.group(4))
    if minutes >= 60 or seconds_part >= 60: raise ValueError("invalid_timestamp")
    return hours * 3600 + minutes * 60 + seconds_part + millis / 1000

def compare_cues(cues, anchors, tolerance=0.25, max_items=5000):
    findings, previous, alignment_unverified = [], None, False
    for index, cue in enumerate(cues):
        if index >= max_items:
            findings.append({"kind": "item_limit_reached"}); alignment_unverified = True; break
        start, end = seconds(cue["start"]), seconds(cue["end"])
        if end <= start: findings.append({"index": index, "kind": "non_positive_duration"})
        if previous is not None and start < previous: findings.append({"index": index, "kind": "start_out_of_order"})
        previous = start
        if index >= len(anchors):
            findings.append({"index": index, "kind": "anchor_missing"}); alignment_unverified = True; continue
        anchor = anchors[index]
        if abs(start - anchor["start"]) > tolerance or abs(end - anchor["end"]) > tolerance: findings.append({"index": index, "kind": "outside_alignment_tolerance"})
        if cue.get("speaker") != anchor.get("speaker"): findings.append({"index": index, "kind": "speaker_token_mismatch"})
    inspected_cues = min(len(cues), max_items)
    for index in range(inspected_cues, min(len(anchors), max_items)):
        findings.append({"index": index, "kind": "cue_missing_for_anchor"}); alignment_unverified = True
    if len(anchors) > max_items:
        findings.append({"kind": "anchor_limit_reached"}); alignment_unverified = True
    if alignment_unverified: findings.append({"kind": "alignment_unverified"})
    return findings

The function bounds the number of inspected items and emits stable classes without copying text or media identifiers. A cue without a corresponding anchor is anchor_missing, while an extra anchor without a cue is cue_missing_for_anchor; either state is unverified alignment, not a pass. A real implementation also needs to parse cue identifiers, settings, voice spans, UTF-8 errors, and multi-line payloads under its chosen parser contract. Keep parser failures separate from a valid cue whose speaker or anchor does not match.

Interpret overlap, gaps, and speaker changes locally

For each cue, record cue identifier, start, end, duration, speaker-token state, anchor reference, tolerance policy, overlap state, gap to the next cue, and disposition. Do not call a gap a missing transcript unless the track contract says every spoken interval must be represented. Do not call an overlap invalid unless the track purpose or local policy forbids it.

Interpret overlap, gaps, and speaker changes locally (table)
ObservationSafe interpretationNext action
Header contract failsThe selected file is not the stated WebVTT formPreserve source and classify header failure
Cue end is not later than startThe cue interval is structurally invalidHold the cue; do not guess duration
Cue starts decreaseCue order conflicts with the timing rulePreserve identifiers and request correction
Cues overlapIntervals overlap under a track-specific choiceCompare track purpose and overlap policy
Gap exists between cuesNo cue covers that intervalCompare anchors; do not infer missing speech
Speaker token changesAnnotation changed between cuesCompare approved mapping; do not infer identity
Token matches anchor within toleranceStructural alignment observation passedKeep tolerance and anchor source; do not infer text accuracy
No approved anchor existsAlignment cannot be measuredMark UNVERIFIED and avoid a pass claim
Limit reached or cue parse failedCoverage or syntax is incompleteRetain counts and stable classes; do not publish raw payload

If a cue contains a voice span, store a normalized token such as SPEAKER_A only when the approved policy permits it. A speaker token can still be identifying when the track is small, so use synthetic labels or approved category codes. The same caution applies to words: a timing match does not validate what was said.

Keep diagnostics safe and the next step qualified

A public report can contain cue indexes, durations, gap and overlap counts, stable speaker-token states, tolerance, anchor type, and parser version. It should not contain raw transcript text, voice names, private paths, audio, faces, or unbounded parse errors. Keep the raw transcript within the owner-approved handling boundary.

Pair this check with the timestamp and timezone guide and data provenance log. Those resources own general timestamp semantics and source, rights, and processing evidence; this guide owns bounded cue, speaker-token, and anchor alignment observations.

After the owner has a supported non-health scope, authority to describe the transcript, and a metadata or synthetic alignment packet, the qualified appraisal request path may be a next preparation step. It does not validate transcripts, identify speakers, certify accessibility, produce a quote, match a buyer, issue a legal opinion, or grant a license. Keep raw speech outside this guide and within the owner-approved handling boundary.

Takeaways

  • Validate WebVTT header, UTF-8 contract, cue start order, and positive duration before semantic review.
  • Treat overlap and gaps as track-policy questions, not universal errors.
  • Compare speaker tokens to approved synthetic or controlled anchors, and never treat labels as identity proof.
  • Record alignment tolerance and anchor source; no anchor means unverified measurement.
  • Publish stable counts and classes, not raw speech, private labels, or media paths.

Sources

  1. World Wide Web Consortium: WebVTT: The Web Video Text Tracks Format (opens in a new tab)
  2. World Wide Web Consortium: WebVTT presentation (opens in a new tab)

Use the appraisal path after the source and bounded transcript alignment packet are organized.

It does not validate transcripts, identify speakers, certify accessibility, create a quote, match a buyer, or grant a license.