Instagram transcript: SRT or VTT — which file do you need?
Take SRT unless something asks you for VTT by name. The two files hold the same cues in the same order and differ by 8 bytes of header, one character in each timestamp — a comma in SRT, a period in VTT — and the escaping of three characters. Measured on this machine by running this site’s own writers, 100 cues of one character each come out as 3,591 bytes of .srt and 3,599 bytes of .vtt. SRT is the file an editor imports and an upload box accepts; VTT is the file a browser loads through a <track> element, and a VTT without its 8-byte header is not a VTT at all.
The rest of this page is the arithmetic behind that — where the 8 bytes sit, what a cue costs before any words are written, why one file escapes & and the other refuses to, what happens when every cue is zero length, and what the three pages that outrank this one say about the choice across 111,520 characters of their own Instagram copy. It is one gap and one answer: if you already have the words and only want to know which file to hand to which program, the paragraph above is the whole of it.
The difference is eight bytes, a comma and a period
Both writers are six lines of code in the same file. buildSrt() at line 382 and buildVtt() at line 385 emit the same block for every cue — an index, a timing line, the text, a newline — and differ in three places that can be counted. Running them on 100 cues of one character each, on this machine, gives 3,591 bytes for the .srt and 3,599 bytes for the .vtt.
- The header is the whole 8-byte gap. 3,599 − 3,591 = 8, and those 8 bytes are the string
WEBVTTfollowed by a blank line. It is not decoration: a WebVTT file must begin with that line, and a browser handed a file without it does not treat the contents as cues. SubRip has no header at all, which is why the.srtstarts directly with the number 1. - The separator costs nothing, because the stamp is fixed width.
stamp()rounds to whole milliseconds and then pads hours, minutes and seconds to two digits each, so00:00:01,234and00:00:01.234are both 12 characters and01:00:00.500is 12 as well. Swapping the comma for a period changes one byte without changing the length, so the 3,599-byte file is not 1 byte bigger than the 3,591-byte one for that reason — it is 8 bytes bigger, all of it header. - VTT escapes three characters and SRT escapes none. A cue reading
R&Dmeasures 36 bytes as.srtand 48 bytes as.vtt: the 8-byte header plus 4 bytes, because&becomes&. Every 1,000 ampersands in a transcript therefore adds 4,000 bytes to the.vttand exactly nothing to the.srt. The comment abovevttText()at line 367 explains why SubRip is left alone: writing&into an.srtshows the viewer six literal characters, which is worse than the problem it would solve. - Both number their cues, for different reasons. The index is mandatory in SubRip and optional in WebVTT, where the line before a timing line is a cue identifier that parsers ignore. This tool writes it either way, so 100 cues carry 3,392 bytes of scaffolding before a single word: 3,200 fixed bytes plus 192 bytes of index digits, since cue 100 needs three characters and cue 1 needs one.
.srt renamed to .vtt still contains no header and a .vtt renamed to .srt still does.Which one goes where
The decision is about the reader, not the file. A person imports an SRT into an editor or drops it into a caption upload box; a browser loads a VTT through the <track> element, and WebVTT is the only text track format browsers implement. That single split accounts for nearly every request you will meet, and it is why the fallback is SRT: more things read it.
- SRT for editors and upload boxes. Premiere Pro, Final Cut Pro and DaVinci Resolve all import
.srtas a caption file, and the subtitle field on most publishing forms asks for one. The 3,591-byte file above is exactly what those importers expect: an index, a timing line with a comma, the text, a blank line, repeat. - VTT for a web page. If the consumer is a
<track src="transcript.vtt">, the file must be WebVTT, must open with the 8-byte header, and must use periods. The 3,599-byte file is the one that element can load; handing it a.srtproduces no captions at all, and the failure is silent — the player simply shows nothing, with no error in the console. - Neither is a document, and the MIME type will not help you tell them apart. Both downloads are written as
text/plain;charset=utf-8at line 536 of the 22,349-byte app.js, so the browser has no idea which one it is holding; only the extension and the first line distinguish them. A.vttopens in Notepad exactly like a.srt. - If you can only take one, take SRT. A 40-cue Reel is 1,430 bytes as
.srtand 1,438 bytes as.vtt; the 8 bytes are not the argument. The argument is that an importer which wants VTT will say so, and an importer which wants SRT will usually choke on a header line it reads as a cue number.
<track> element: the player renders nothing and the console stays empty, which is why renaming a file never fixes this — the header has to be written, and only one of the two writers writes it.What this tool actually writes, line by line
Everything below was read from the deployed app.js — 22,349 bytes, the same file the page you are on loads — or measured by calling its functions on this machine. None of it is a description of the formats in general; it is what comes out of the two download buttons.
- The timestamp is always 12 characters, whatever the length of the video. Hours are padded to two digits, so a 1-second cue and a cue at 3,600 seconds both spend 12 bytes on a start and 12 on an end. A 20-minute Reel pays the same 24 bytes per cue as a 5-second one; nothing about file size grows with duration except the number of cues.
- Each cue costs 32 bytes before its index digits and its words. Two newlines, two stamps and the arrow account for those 32; add the index (1–3 characters) and the text. That is how 100 cues of one character land on 3,392 bytes of scaffolding and 3,591 bytes of file — 94.4% of the download is structure, not speech.
- A cue with no duration is dropped, and an all-dropped run writes no file at all.
subtitleCues()at line 365 keeps only cues where the end is after the start. If nothing survives, the button shows an error string — “This run produced no cue with a real duration, so there is no subtitle file to make.” — and a 0-byte.srtis never created, so a file that exists is a file with at least one cue in it. The.txtbutton is written fromsegmentsbefore that filter runs, which is why the two downloads can disagree: fed 4 chunks on this machine, 3 became segments and only 2 became cues. - The filename is hardcoded. Line 520 builds it as
transcript.${kind}, which is 0 characters of title, date or source in the name: every download istranscript.srtortranscript.vtt, and the second Reel you export lands beside the first with the same name. - Line breaks inside a cue are collapsed before writing.
toSegments()replaces runs of whitespace with one space, because a blank line ends a cue in both formats and a paragraph break inside one would truncate it. That is also why 100 cues of one character each still parse as 100 cues in a 3,591-byte file rather than as a handful of broken ones. - Only the VTT path runs the three replacements.
&,<and>become entities in.vtt, so a transcript with 1,000 ampersands grows by 4,000 bytes; the.srtpath leaves every character alone and grows by 0.
What the three pages that outrank this one say about the choice
Across the 10 Instagram pages the three sites publish — 111,520 characters of body text once the heading lists and the scraper’s metadata are stripped, because a reader never sees those — the two format names appear 10 times in total. Not one of those mentions explains when to use which, and the phrase “difference between” appears 0 times in the 226,947 characters of the whole benchmark corpus.
- getthescript.app names both formats once, in a list. Its Instagram transcript page is 2,847 characters long and the only mention is “Export TXT, SRT, or VTT for subtitles, schedulers, and repurposing workflows”. That is an inventory of outputs, not a rule for picking one, and the other 2,846 characters say nothing about the difference.
- wayin.ai comes closest, and still treats them as interchangeable. Its 7,304-character Instagram page says “After generating your transcript, select SRT or VTT from the export menu” and calls them “timestamped formats (SRT / VTT) for subtitle workflows and video editing pipelines”. The nearest thing to a comparison anywhere in the corpus is its YouTube FAQ, which answers “How do I download a YouTube transcript as SRT or VTT?” with “Both formats include timestamps, so they are ready for subtitle editing and publishing” — true, and silent on which program opens which.
- speakapp.com names neither format on any Instagram page. Its three Instagram pages total 4,758 characters on the transcript page alone and contain 0 instances of “srt” and 0 of “vtt”; the only subtitle reference is a customer line, “I use it for subtitle creation all the time”. Whatever it hands back, it does not offer you the choice in writing.
- None of the three mentions the header. Across 226,947 characters the string “WEBVTT” appears once, in a getthescript.app feature bullet that reads “exportable in TXT, SRT, and WebVTT”, and never as the thing that decides whether a player will load the file. That is the single fact that matters most when the file is going into a web page rather than an editor.
How to tell which file you are holding
Three checks, each a few seconds, and they settle it without opening any software: the first line, the character before the milliseconds, and the size. All three work on a file you downloaded weeks ago and cannot remember the source of.
- Look at the first line.
WEBVTTmeans VTT; a bare number means SRT. This is the 8 bytes that separate a 3,599-byte.vttfrom a 3,591-byte.srt, and it is the one difference that changes behaviour rather than appearance. - Look at the character before the milliseconds. A comma is SubRip, a period is WebVTT. Both are 12 characters wide, so the timing column lines up identically in a text editor and you cannot tell them apart by eye unless you look at that one position — position 9 of the stamp, right after the seconds.
- Do not rename one into the other. Changing a
.vttto.srtleaves the 8-byte header in place and leaves&where an ampersand should be, so an SRT parser readsWEBVTTas the first cue number and loses the file. A renamed 3,599-byte.vttis still 3,599 bytes and still not an.srt: the extension is a label, not a conversion.
Can I feed a .vtt to a program that asks for .srt?
Only if that program parses WebVTT, and most importers that ask for .srt do not. The failure is not a warning: the header line sits where the first cue index should be, so the parser either drops cue one or rejects the file. Convert it by deleting the 8-byte header, swapping periods for commas and unescaping the entities — or simply export the 3,591-byte .srt instead of the 3,599-byte .vtt, which is one click and no editing.
Why is the file so much bigger than the text I copied?
Because the words are the small part. 100 cues of one character occupy 3,591 bytes, of which 3,392 are scaffolding — 3,200 fixed bytes plus 192 of index digits — and the remaining 199 bytes are the characters and the blank lines between blocks. Add real sentences and the text share rises; at 50 characters a cue the same 100 cues come to 8,491 bytes, so the structure is still a third of the file.
Does the timestamped transcript download as SRT or VTT?
Both, and both carry the same stamp. The timestamped view on screen and the two subtitle files are three renderings of one set of cues: the screen shows the 12-character stamp in front of each line, and buildSrt() and buildVtt() write the same 12 characters with a comma or a period, producing 3,591 bytes and 3,599 bytes from the same 100 cues. There is no third file format hiding behind the timestamped view.
Why did the download button give me an error instead of a file?
Because no cue survived the duration filter. subtitleCues() drops every cue whose end is not after its start, and if all of them go, the button reports “This run produced no cue with a real duration, so there is no subtitle file to make.” instead of writing something. A 0-byte download never happens: either you get a file with at least one cue or you get that message, and the words themselves are still in the panel to copy.
Which format carries speaker labels?
Neither, and that is a property of the cues rather than of the container. A cue in this tool has three fields — start, end and text — and 0 of them names a voice, so both the 3,591-byte .srt and the 3,599-byte .vtt come out with no label at the front of any line. Separating speakers is a different problem with different routes.
Is the .srt always smaller?
Yes, and by a fixed 8 bytes plus 4 for every escaped character. The header is the only structural difference, so 3,591 against 3,599 stays 3,591 against 3,599 no matter how long the transcript is; the gap only widens when the text contains ampersands, angle brackets or the arrow sequence that VTT has to neutralise. Size is not a reason to choose between them at any length you will meet on Instagram.
Last checked: 26 October 2026. The byte figures were produced on this machine by extracting stamp(), vttText(), buildSrt() and buildVtt() from the deployed app.js and running them on generated cues: 100 cues of one character gave 3,591 bytes as .srt and 3,599 bytes as .vtt, 40 cues gave 1,430 and 1,438, one cue of two characters gave 35 bytes, a cue reading R&D gave 36 and 48, and 100 cues of 50 characters gave 8,491. The 4 chunks that became 3 segments and 2 cues came from running toSegments() and subtitleCues() together on a hand-built input holding one empty-text chunk and one zero-length cue. The 3,392 bytes of scaffolding is 3,200 fixed bytes plus 192 index digits, counted from the same output; the 12-character stamp length was read off the pad() calls at line 351 and confirmed on a cue at 3,600 seconds. The source facts — 22,349 bytes of app.js, subtitleCues() at line 365, the three replacements at line 377, the two builders at lines 382 and 385, the hardcoded transcript.${kind} at line 520 and the text/plain;charset=utf-8 Blob at line 536 — were read from the deployed file, not from memory. The competitor figures cover 10 Instagram pages and 111,520 characters of body text, and 226,947 characters across the 33 files in this site’s benchmark directory, measured after the heading lists were stripped; the sentences quoted from getthescript.app, speakapp.com and wayin.ai are reproduced exactly as they appear there. Which programs import .srt is general knowledge about those editors rather than something measured here; the claim that a browser track element takes only WebVTT is from the HTML specification.
If the words are still inside the video, a video with no captions covers why a missing caption track changes nothing here, and the timestamps page covers what the 12 characters in front of every line are made of. Who said what explains why neither subtitle file can label a speaker, what to do with a transcript covers the downstream uses of both files, and Instagram’s own captions covers the route that never produces a file at all. The 3,840,000 bytes of audio behind a one-minute cue list are worked out on the upload page, next to the 79.7 MB model that decodes them.