
How to Fix Subtitle Timing: Offset, Drift, and Local Errors
Subtitles appear two seconds early. You shift them later, the opening looks right, and the ending is still wrong. Fixing subtitle timing starts with measuring the error pattern before choosing a correction.
Measure subtitle timing against the exact delivery video
Keep the original subtitle file and identify the exact video export. Match distinctive spoken words to cue boundaries. Measure the same event in each timeline, rather than comparing a subtitle's display end with the start of a sentence.
The fictional anchors below use seconds from the start of the files:
| Anchor | Subtitle time s | Observed speech time v | Difference v−s |
|---|---|---|---|
| Opening | 10 | 12 | +2 |
| Middle | 110 | 114 | +4 |
| Ending | 210 | 216 | +6 |
The error grows. Adding two seconds fixes the opening but leaves the ending four seconds early. These values define a timing example, not a recommendation about how early captions should appear. Apply the project's caption style after restoring the timeline relationship.
Choose a shift, a scale, or a local repair
| Pattern | Suitable first approach | What to inspect |
|---|---|---|
| Similar difference at every anchor | Add the same offset to all cue boundaries | File start or export offset |
| Difference changes approximately linearly | Map two anchors, validate a third | Time-scale mismatch; do not assume the cause is frame rate |
| Difference jumps after an edit | Split the affected region and re-align | Added or removed media, different cuts |
| Only individual words are wrong | Re-align those passages against audio | Transcription boundaries and speech alignment |
Calculate the two-anchor correction
For subtitle time s, use corrected time v = a × s + b. From the opening and ending anchors:
a = (216 - 12) / (210 - 10) = 1.02
b = 12 - 1.02 * 10 = 1.8
v = 1.02 * s + 1.8
Middle check: 1.02 * 110 + 1.8 = 114The middle point validates this example. For another video it may disagree, showing that one global transform is inappropriate. Two anchors always fit a line; the unused checkpoint is what helps reveal a bad assumption.
Apply the same transform to both start and end times. Here a cue at 10–12 seconds becomes 12–14.04 seconds. The following JavaScript operates on numeric seconds, before an SRT or VTT serializer:
function retimeCue(cue, a, b) {
if (!Number.isFinite(a) || a <= 0 || !Number.isFinite(b)) {
throw new Error("Invalid timing transform");
}
const start = Math.round((a * cue.start + b) * 1000) / 1000;
const end = Math.round((a * cue.end + b) * 1000) / 1000;
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end <= start) {
throw new Error("Invalid cue interval");
}
return { ...cue, start, end };
}Reject negative times for manual review rather than silently clamping them to zero. Inspect overlaps after transformation and rounding. Some overlap is intentional in multi-speaker captions, so a checker should report it instead of automatically deleting a cue.
Use AI to organize measurements, not invent them
Analyze the supplied subtitle-to-video anchors.
Classify constant offset, approximately linear drift, local discontinuity,
or insufficient evidence. Use only the measured positions.
If proposing v=a*s+b, show the two fitted anchors and test an unused anchor.
Do not assume a frame-rate cause without metadata.
Keep cue IDs and text unchanged. Return a proposed transform, residuals,
affected region, and export checks. Do not invent word timestamps.
Inputs: exact video version, cue file, measured anchors, caption-style rules.Start with the three measured anchors in this article. Ask for the proposed transform and unused-point check; accept the analysis only if it yields a=1.02, b=1.8 and the middle value 114. Apply it to a copy with the deterministic function, then check playback.
Export and test the corrected file
Preserve cue IDs, language, text, and speaker markers. Serialize the format's actual timestamp syntax: SRT uses a comma before milliseconds, while WebVTT uses a period. Reopen the result with the delivery video and inspect opening, middle, ending, scene cuts, short cues, and overlaps.
For chunked transcripts, first convert local positions to global source time using each chunk's offset. Applying a subtitle correction to still-local times can create a second error. When only one region differs, keep a record of its transform and boundaries instead of stretching unaffected dialogue.
If there are missing sentences or duplicated speech, time arithmetic cannot repair the text. Return to the transcription. For word-level alignment, use a tool that actually reads the audio and supports the language; then sample its output. An apparently precise timestamp is not proof that a word was aligned correctly.
FAQ
Do I add or subtract a positive offset?
This article defines it as speech time minus subtitle time. Positive means move the subtitle later. Check the tool's own sign convention.
Can a flat shift fix growing drift?
It can align one location. A changing error needs a validated scale adjustment or local alignment.
Does drift prove the frame rate is wrong?
No. Check media metadata and edits; the observed pattern alone does not establish its cause.
Can I correct burned-in subtitles this way?
A sidecar timing file can be edited. Text already rendered into video requires a different media-editing process.
Should transcript timestamps use the same transform?
Only if they share the same source timeline relationship. Restore chunk offsets first and validate known points.
How much of the export should I check?
At least the measured anchors plus edit boundaries and flagged intervals. Set broader sampling according to the delivery requirements.
Sources
- Subtitle Edit: main-window features: time adjustment and synchronization options.
- WebVTT specification: text-track timestamp format.


