Subtitles go out of sync for one of four reasons, and each needs a different fix. The whole file can be early or late by the same amount (an offset). It can start right and slide further off as the video plays (a frame-rate mismatch). It can be fine until one point and then jump (a different cut of the video). Or the file can be roughly in place while individual lines start late, end late or hang over silence (bad line timing, which is what most auto-generated subtitles suffer from).
You can tell which one you have in about two minutes by checking two lines, one near the start and one near the end. This guide shows how, gives the fix for each case, and then digs into the fourth kind with numbers: we built test audio where we knew the exact moment every sentence started and ended, ran it through Whisper three ways, and measured how far the subtitle timings landed from the speech.
Step 1: find out which kind of out of sync you have
Pick a line near the beginning of the video and a line near the end. For each one, write down two times: when the line is spoken in the video, and the start time the subtitle file gives it. The difference is the offset at that point.
| What you see | Offset near the start | Offset near the end | Cause | Fix |
|---|---|---|---|---|
| Everything is early or late by the same amount | 2.0 s late | 2.0 s late | Constant offset: a different intro, logo or lead-in | Shift every line by the same amount |
| Starts in sync, gets worse steadily | 0.2 s | 2 min 34 s early | Frame-rate drift: subtitles made for a different frame rate | Stretch the timings (frame-rate conversion or two-point sync) |
| In sync, then suddenly off from one scene onward | 0 s | 12 s late, starting from one scene | A different cut: a scene, recap or ad break added or removed | Shift only the lines after the jump |
| On average in place, but lines pop in late, linger, or show during silence | varies by line | varies by line | Bad line timing, typical of auto-generated subtitles | Retime the bad lines, or regenerate with word-level timing |
Two checks are enough to tell the first two apart: if both offsets are about equal, it's a constant offset. If the second is much bigger, divide it by how far into the video that line is. A steady ratio of about 4% is the signature of a frame-rate mismatch (more on the numbers below).
Fix 1: the whole file is early or late (constant offset)
This is the most common case and the easiest fix. Common causes: the subtitle file was made for a version with a longer studio logo, a "previously on" recap, or a few seconds of black at the start.
To watch right now, adjust it in the player. VLC has a subtitle delay setting. On Windows and Linux the default hotkeys are G and H, which move subtitles 50 ms earlier or later per press, according to VLC's hotkey list. The Mac build uses different keys, so check Preferences → Hotkeys there. Most other players (mpv, PotPlayer, Plex, Kodi) have a similar subtitle offset setting. The change only lasts for that playback session.
To fix the file for good, shift every timestamp. Two ways:
- In the browser: load the file into the free SRT editor, optionally with the video, enter the shift in seconds (negative to move earlier) and apply it to all cues. Play a few lines against the video to confirm, then download. The file stays on your computer.
- On the command line, ffmpeg can do it:
ffmpeg -itsoffset 2.5 -i in.srt out.srtmoves every cue 2.5 s later.
One ffmpeg trap we hit while testing: a negative offset bigger than the first cue's start time gets quietly shortened. On ffmpeg 8.1.1, shifting a file whose first cue starts at 1.0 s by -itsoffset -1.5 moved every cue only 1.0 s earlier, just enough to put the first cue at 0:00. Every later cue ended up 0.5 s late, and ffmpeg printed no warning. Our editor clamps each cue at 0:00 separately instead, so only cues that would start before the video begins get squashed, and every other cue moves by the full amount. If you use ffmpeg for negative shifts, check the second cue, not the first.
Fix 2: subtitles drift further off as the video plays (frame rate)
If the subtitles start in sync and are a few seconds off after half an hour and minutes off by the end, the file was timed against a version of the video that runs at a different speed. The classic case: subtitles made for a 25 fps European (PAL) release played against a 23.976 fps release of the same film. The PAL release runs about 4% faster, so every timestamp is about 4% too small.
Here's how far off that gets, by how long into the video you are:
| Subtitles made for | Played on | Off after 10 min | 30 min | 60 min | 90 min |
|---|---|---|---|---|---|
| 25 fps | 23.976 fps | 25.6 s | 1 min 17 s | 2 min 34 s | 3 min 51 s |
| 25 fps | 24 fps | 25.0 s | 1 min 15 s | 2 min 30 s | 3 min 45 s |
| 24 fps | 23.976 fps | 0.6 s | 1.8 s | 3.6 s | 5.4 s |
(Ratio 25 / 23.976 = 1.0427, so a cue at 60:00 belongs at 62:34.) The last row is the sneaky one: 0.1% looks like nothing, but it puts a feature film's last scenes 5 to 7 seconds off.
Shifting can't fix this, because the error grows. You need to stretch the timings:
- If you know both frame rates, use a frame-rate conversion. In Subtitle Edit that's Synchronization → Change frame rate. Getting the direction backwards doubles the problem, so test one late line before saving.
-
If you don't, use two-point sync: tell the tool the correct time of one line near the start and one near the end, and it scales everything in between. Subtitle Edit calls this Point sync. The math is a straight line:
new time = a × old time + b, whereaandbcome from your two corrected lines.
Our SRT editor only shifts; it doesn't stretch. For drift, use a tool with point sync, then load the result into the editor if you want to check it against the video.
Fix 3: in sync, then suddenly off from one point (a different cut)
If the first half is perfect and everything after one scene is late by the same amount, the subtitles came from a different edit: a director's cut, a TV version with a recap, or a recording with an ad break. Find the first line that's wrong, measure its offset, and shift that line and everything after it. Subtitle Edit can shift just selected lines (select from the first bad line to the end). If there are several jumps, repeat for each section.
Fix 4: lines start late, linger, or show during silence (bad line timing)
The first three problems are about the whole file. This one is about individual lines, and it's the one you'll meet in auto-generated subtitles: a line that appears a beat late, stays on screen through a long pause, or shows up during the intro music before anyone speaks.
What counts as "in sync" here? Netflix's subtitle timing guidelines are the strictest common reference. A subtitle should appear on the first frame of the audio, with 1 to 2 frames either way accepted (at 24 fps, a frame is about 42 ms). The out-time should ideally be at least half a second after the audio ends, provided the line doesn't visibly linger. So the target is: appear with the voice, and leave about half a second after it.
We wanted to know how close AI subtitles get to that, and what goes wrong when they miss. So we measured it.
The test: speech with known timings
You can't measure timing errors without knowing the right answer, and nobody knows the exact start of every word in a real recording. So we built one where we did:
- We wrote 30 sentences (a short history of a lighthouse) and had four macOS voices read them (US, UK, Australian and Irish English), cut to the exact start and end of the speech.
- We joined them with gaps of 0.35 to 1.4 seconds, plus three long pauses of 6, 12 and 25 seconds, the kind you get in interviews and lectures. That gave a 2 min 49 s track where we knew every sentence's start and end to the millisecond.
- We made four versions: clean; with 20 seconds of synthetic intro music before the first word; with a music bed under the whole thing; and with pink noise under the whole thing.
- We transcribed each version with Whisper (
smallmodel, faster-whisper 1.2.1) in three setups:- Plain Whisper: the library defaults, timing each line from Whisper's segment timestamps. This is what you get from many basic Whisper wrappers.
- Word timestamps: the same, plus word-level timing, with each line starting at its first word and ending at its last.
- Word timestamps + VAD: word timing plus a voice activity detector that skips non-speech before Whisper sees it. These are the settings ScribeToAny's own engine uses in its fast mode.
- For every line that starts or ends a sentence, we compared its time with the true time.
The results
| Setup | Lines starting within ±0.25 s | Lines ending more than 0.5 s late | Longest a line stayed up over silence | Sentences lost |
|---|---|---|---|---|
| Plain Whisper | 48–89% | 83% (86 of 104) | 25.0 s | 3 (clean version) |
| Word timestamps | 64–72% | 0% | 5.2 s | 0 |
| Word timestamps + VAD | 62–90% | 0% | 1.4 s | 0 |
Ranges cover the four versions (clean, intro music, music bed, noise). Here's what's behind them.
1. Plain Whisper's lines don't end, they wait for the next one. In the clean version, all but one line ended exactly where the next one started. Whisper's segment timestamps run back to back, so a line stays on screen until the next line replaces it. Over normal gaps that means lines end about 0.9 s late (median), on the edge of Netflix's half-second allowance or past it. Over a long pause it's worse: one line, "Next to it is the keeper's logbook from the winter of 1947", was spoken in 4 seconds and then stayed on screen through another 25 seconds of silence. To a viewer, a subtitle hanging over silence looks like the subtitles are out of sync, even though every start time is fine.
2. Plain Whisper lost three sentences after the long pause. In the clean version, the three sentences after the 25-second pause never appeared: the transcript jumped from the line before the pause to the fourth sentence after it. The line after them, "The keeper rowed out twice in a storm", went up 11 seconds early, over the missing ones. Nothing in the output flagged the gap. The same audio with intro music in front kept all three. If a transcript gets out of step after a long silence, check whether lines are missing before you start retiming.
3. Intro music put the first line at 0:00. With 20 seconds of music before the first word, plain Whisper made the first subtitle the single word "The", from 0:00.00 to 0:20.64, and put the rest of the sentence in the next line. So a lone "The" sits on screen for the whole intro. This is the classic "first subtitle is way too early" complaint. With VAD the first line started at 0:20.08, 0.42 s before the voice, because the detector had removed the music before Whisper ran.
4. Word timestamps fix the hanging but end every line early. With word-level timing no line ever hung over a pause for more than a few seconds, and with VAD no more than 1.4 s. But the ends came out early across the board: in every version, all or all but one of the line endings came before the voice stopped, by a median of 0.18 to 0.21 s. Starts were early too, by a median of 0.10 to 0.16 s. We checked this against our ground truth: setting the speech-end point with a stricter loudness threshold moved it by only about 0.03 s, so the early bias is real. Measured against Netflix's target of leaving half a second after the voice ends, word-timed lines leave about 0.7 s too soon.
5. Noise hurts plain Whisper's starts most. Under pink noise, only 48% of plain Whisper's lines started within a quarter-second of the voice, and three were more than a second off. With word timestamps it was 66%, with no line more than 0.72 s off.
What we didn't test: synthetic voices are cleaner and more regular than people, so real recordings will likely do somewhat worse on every setup. This was one model (small; our engine's other modes use larger models, which we didn't test here), English only, 30 sentences, one run per setup. The pattern is what matters here (segment timing hangs over silence, word timing ends early, VAD fixes the intro), not the exact percentages.
What to do with auto-generated subtitles
- Check three places before anything else: the first line (is it on screen during the intro?), the line before every long pause (does it hang over the silence?), and the line after it (is anything missing?).
- If lines hang over pauses, end each line at its last word. A tool that times from word timestamps will do this for you. If you're stuck with segment-timed lines, retime the ones before long pauses by hand.
- Push line ends out a little. Word-timed lines tend to vanish just before the voice stops. Extending each end by about half a second, where the next line leaves room (Netflix wants at least 2 frames between lines), puts them close to the broadcast convention, and it also gives viewers more time to read. Our subtitle reading speed experiment found the same move cut the share of too-fast lines from 68% to 29%.
- Strip the intro before transcribing, or use a tool with voice activity detection, if the video opens with music.
How ScribeToAny does it: our engine uses the third setup: word-level timestamps with a voice activity detector tuned to keep quiet speech. That avoids hanging lines, the 0:00 intro line and, in this test, lost sentences. But it also had the early-ending problem: its lines ended about 0.2 s before the voice. So after this test we changed how the engine ends lines. Each line now stays up to half a second past its last word, never into the next line, and any gap left under half a second is closed to 2 frames, following Netflix's rules. Starts don't move. We ran the same word timings through the updated code. Line ends went from a median 0.2 s before the voice to 0.38 to 0.41 s after it, and no lines overlapped. As a side effect, the lines reading faster than 17 characters per second dropped from 14 to 20 of 30 per version to 1 to 4. You can still edit any line's start and end times in the transcript's QC view, or load the exported file into the SRT editor with the video and adjust it there.
How to keep subtitles in sync in the first place
- Make subtitles from the exact file you'll publish. Re-export after the final edit. Most offset and cut problems come from subtitling a rough cut.
- Note the frame rate of the version the subtitles were made for, and keep it in the file name if you work with several releases.
- Check two points, not one. One correct line proves nothing about drift.
- Prefer word-timed subtitles for anything with pauses: interviews, lectures, podcasts. If you're generating them, the subtitle generator makes a timed SRT or VTT from your audio or video in about 98 languages.
FAQ
Why are my subtitles a few seconds behind? If they're behind by the same amount all the way through, the file was made for a version with a longer intro. Shift every line earlier by that amount. If they get further behind as the video goes on, it's a frame-rate mismatch and needs stretching instead.
Should subtitles appear before the person speaks? Netflix's rule is on the first frame of audio, with one or two frames of tolerance. In our test, word-timed AI subtitles appeared 0.10 to 0.16 s early (median), a few frames. In our view that matters far less than lines that appear late or stay on screen through a silence.
Can I fix subtitle sync without installing anything? For a constant offset, yes: load the file and the video into the browser-based SRT editor, shift all lines and download. For frame-rate drift you need a tool that can stretch timings, such as Subtitle Edit's point sync.
Out-of-sync subtitles feel like one problem, but it's four, and the two-minute check tells you which one you've got. Offsets need a shift, drift needs a stretch, cuts need a partial shift, and auto-generated subtitles need their line ends looked at, especially around silence. We hadn't expected the silence to matter more than the noise, but in our test it did.
Originally published on the ScribeToAny blog.

Top comments (0)