IGTranscript

Does transcribing an Instagram video upload the video?

It depends on which tool you use, and the difference is where the model runs — not a policy you have to take on trust. On this page, no. The whole client that would have to do the uploading is one 22,349-byte script, the file you choose is read by that script's own code rather than handed to a form, and every request the page makes is a GET for a public file, so there is no request that could carry your video. On the three best-known Instagram transcript tools, yes: all three run the recognition on a machine that is not yours, and their own pages say so in the vocabulary of servers and clouds. The sentence none of them writes is "the video never leaves your device" — the strongest claim any of them makes is that the file is not kept afterwards.

Each is quoted exactly below, with its source page.

InVideo WW

"Not stored" and "not sent" are different claims

A model that runs on a company's hardware needs the media on that hardware. There is no arrangement in which a server transcribes a file it never received, so the honest reading of all three pages is that the file is uploaded, the recognition happens on their machine, and the reassurance on offer is about the retention period rather than about the transfer. That is a defensible trade — the alternative is asking every visitor to download a 79.7 MB speech model before they can read one Reel — but it is a different thing from what the question asks, and none of the three quite says which of the two it is answering.

What this page sends instead

The checkable version of "no upload" is an inventory of requests, and the inventory is short. The script makes exactly one fetch() call and exactly one dynamic import(), to two hosts: cdn.jsdelivr.net for the recognition library, and huggingface.co for the speech model and its configuration. Both are GETs for public files that are identical for every visitor. The model is the large part of it — 23.20 MB of quantised encoder plus 53.69 MB of quantised decoder, so 76.89 MB of that 79.7 MB total is weights — and not one of those bytes depends on what you chose. The only thing your file contributes to the network is 0 bytes.

The entire request list of the page, and what the model download is made of. The script makes one fetch to a content delivery network for the recognition library and one dynamic import to a model host for the speech model and its configuration, which is two GETs in total. Of the seventy-nine point seven megabyte model, twenty-three point two megabytes are the quantised encoder and fifty-three point six nine are the quantised decoder. The file the visitor chooses contributes zero bytes to any of it. Your file contributes 0 bytes to the network The whole request list is two GETs, and neither one grows when you pick a bigger file. what the page asks for fetch() → cdn.jsdelivr.net the recognition library import() → huggingface.co the speech model and its config Two requests in total, both GETs for public files that are identical for every visitor. what the 79.7 MB model is made of 23.20 MB encoder 53.69 MB decoder 76.89 MB of the 79.7 MB total is weights; the sliver at the right is the configuration. What your file adds to that list: 0 bytes. A 6.3 MB clip and a 1.3 MB clip both transcribed, and neither could have travelled in a GET.
The two rows are the script's entire outbound surface rather than a sample of it: one fetch() to cdn.jsdelivr.net for the recognition library and one dynamic import() to huggingface.co for the speech model and its configuration, which is 2 requests and 0 of them file-dependent. The stacked bar is the download the page does make, split by what it contains: 23.20 MB of quantised encoder plus 53.69 MB of quantised decoder is 76.89 MB of the 79.7 MB total, and the 2.81 MB left over is the configuration. Both figures come from the same measurement: a 6.3 MB, 43-second MP4 and a 1.3 MB, 161-second MP3 each produced a transcript, and since the two GETs above are the only requests the page can make, neither file could have travelled in one. The 43.6 MB alternative checkpoint changes the second bar and nothing else about the list.

How to check it yourself, in one tab

None of this has to be believed. Four checks, in increasing order of effort:

  1. Watch the request list, not the page. Open the developer tools, go to the Network panel, clear it, and then choose a file. On this page the list fills with GETs to cdn.jsdelivr.net and huggingface.co and nothing else, and none of them grows when you pick a bigger file. Measured here, a 6.3 MB, 43-second MP4 and a 1.3 MB, 161-second MP3 both produced a transcript — and since the two GETs in the script are the only requests the page is capable of making, neither of those files could have travelled in one.
  2. Look for the field that is not there. A browser uploads a file through a form with enctype="multipart/form-data", or through FormData, XMLHttpRequest or navigator.sendBeacon. Across this site's 14 files, the count of every one of those is 0, and there is no <form> element anywhere in it. The front page holds 2 <input> elements and their types are file and checkbox; the file one is wired to a change handler that reads the File object inside the tab, which is the part that makes the 22,349-byte script the whole story.
  3. Run it with the network cut. This is the decisive test, and it is one you run rather than a number this page reports. A server-side tool cannot produce a transcript while the tab has no connection, because the media and the model are both somewhere else. Here, once a model has been used its files sit in the browser's own cache — measured, a repeat visit of the same model transferred 0 bytes — so a second run has nothing left to fetch. After one successful run, switch the network off and run a second file: if the transcript still appears, nothing was uploaded, and if the page stops with a download error instead, that error tells you what it still wanted.
  4. Count what is stored. An upload leaves traces on a server; a local run leaves them on your device. Across this site there are 0 calls to localStorage, sessionStorage, indexedDB and document.cookie, and the tool keeps no history at all, so a transcript exists in the tab until you export it. What is on your device afterwards is the cached model — 79.7 MB for the default and 43.6 MB for the smaller one — and nothing whatever about the file you chose.
The network-cut test, in three steps. Run one file so the model is cached. Cut the network. Run a second file. If a transcript still appears, nothing was uploaded; if a download error appears instead, that error names what the page still wanted. Underneath is the request inventory the test is checked against: one fetch and one dynamic import to two hosts, both GETs for public files, and no form, no FormData, no XMLHttpRequest, no sendBeacon and no POST anywhere in the script. The test you run, not the claim you read Turn the network off between two runs. 1. Run one file the model downloads once and is cached 2. Cut the network the tab has nothing left to fetch 3. Run a second file one of two things happens, and they are not alike A transcript appears nothing was uploaded — the audio was decoded inside the tab A download error appears the error names what the page still wanted, and it is not your file What the test is checked against, counted in the script: 1 fetch( and 1 import(, to two hosts — cdn.jsdelivr.net for the library and huggingface.co for the model — both GETs for public files. 0 form elements, 0 FormData, 0 XMLHttpRequest, 0 sendBeacon, 0 POST. The only thing your file contributes to the network is 0 bytes.
The checkable version of "no upload" is a test you run rather than a promise you read. After one successful run the model sits in the browser cache — measured, a repeat visit of the same model transferred 0 bytes — so a second run has nothing left to fetch: if the transcript still appears with the network cut, nothing was uploaded, and if a download error appears instead, that error names what it still wanted. The inventory behind it is one fetch( and one import( to two hosts, both GETs for public files, with 23.20 MB of quantised encoder and 53.69 MB of quantised decoder making up 76.89 MB of that 79.7 MB total, and 0 form elements, 0 FormData, 0 XMLHttpRequest and 0 sendBeacon across the site.

What the tab holds instead of sending

The reason a browser-side tool can answer "no" is that it pays the cost somewhere else, and the cost is memory. Web Audio hands decoded audio back as 32-bit floating-point samples at the file's own rate and channel count, which is 4 bytes for every sample: one second of 48 kHz stereo is 48,000 × 2  × 4 = 384,000 bytes, so 23.04 MB for every minute of it, and a three-minute Reel is 69.12 MB of decoded audio before anything has been recognised.

Then it resamples, because the model wants 16 kHz mono — that is what the RATE = 16000 constant in the script is for. At one channel, 16,000 × 1 × 4 is 64,000 bytes a second, or 3.84 MB a minute. Both buffers are alive at the same time, so the three-minute 48 kHz stereo clip is 69.12 MB decoded plus 11.52 MB resampled: 80.64 MB of your machine's memory to produce a transcript that would have cost an operator nothing.

Longer clips scale the same way. Ten minutes at those settings is 230.4 MB plus 38.4 MB, or 268.8 MB, which is the real reason a 20-minute file is refused on a four-gigabyte machine while a 30-minute one whose audio is 16 kHz mono goes through: the limit is the size of the decoded audio, not the clock. Nothing on that path is a network operation, and that is the trade in one line — you keep the bytes, and you pay for them in RAM instead of in a round trip.

The model itself never sees more than a slice. The script asks for 30-second chunks (chunk_length_s: 30), and 30 seconds of 16 kHz mono audio is 1,920,000 bytes, or 1.92 MB — so the largest single object handed to the recogniser is 1.92 MB no matter how long the Reel is.

Where the bytes go. Inside the tab, a chosen file is decoded to 32-bit float audio, resampled to 16 kHz mono, recognised, and turned into a transcript that stays in the tab's memory. Across the network, two GETs bring public files in: the recognition library and the speech model weights. The one request that would carry the visitor's own video out of the device is drawn crossed out, because on this page it does not exist. Where the bytes go Two downloads come in. Nothing of yours goes out. the device boundary Inside this tab your file, read in the tab decoded audio, 32-bit float resampled to 16 kHz mono transcript, in this tab's memory Over the network cdn.jsdelivr.net GET · recognition library huggingface.co GET · speech model weights your video the request that would carry it Count of these: 0. No code here could send one.
Everything that crosses the boundary from the right is a public file — the recognition library, then 23.20 MB of quantised encoder and 53.69 MB of quantised decoder weights, 76.89 MB of the 79.7 MB the progress bar reports. The arrow in the other direction is the upload, and its count here is 0, which is why the tab rather than a server has to hold 69.12 MB of decoded audio for a three-minute 48 kHz stereo Reel.

Is a browser-side transcript any worse than a server-side one?

Yes, in two measurable ways, and neither of them is about privacy. A server has more compute than a phone, so it transcribes faster and can hold an hour of decoded audio — 1,382.4 MB of it at 48 kHz stereo — without a tab dying; this page works a slice of 1.92 MB at a time and pays for its longer clips in waiting. A server can also take a link, which this page cannot: there is no fetcher here, so you have to bring the file. What you get in exchange is the thing this page is about — the bytes never move, no operator pays anything per job, and the tool keeps working with the network cut.

Which answer applies to you

If the reason you are asking is that you do not want a copy of your video sitting on someone else's machine, the only version of the tool that answers it is the one where the model runs where the file already is, and you can confirm which kind you are looking at in about a minute with the Network panel. If the reason is speed or length, a server-side tool is the better answer and there is nothing wrong with using one — the question worth asking it is not "do you upload my video", because it must, but how long the file stays afterwards. A three-minute Reel is 69.12 MB of decoded audio and an hour-long Live replay is 1,382.4 MB, so that is not a small number of bytes to be leaving around, and it is the figure none of the three puts next to the word "secure".

Last checked: 9 October 2026. The request inventory, the byte counts and the memory arithmetic on this page were derived on 9 October 2026 from this tool's own source — where the constants that matter are RATE = 16000 and chunk_length_s: 30 — and from the Web Audio specification, which fixes decoded samples at 32 bits each; every figure was printed and checked before it was written down. The measured figures (22,349 bytes for the script, 79.7 MB and 43.6 MB for the two models, 6.3 MB and 1.3 MB for the two test files, 0 bytes on a repeat visit of a cached model) were taken on a two-core, four-gigabyte machine in an ordinary browser tab. The three quoted sentences are quoted exactly as published and read on 6 October 2026, with the page named for each. Figures that could not be derived are absent rather than estimated.

Everything above describes the same tool as the home page — the file picker, the language setting and the export buttons. The privacy page is the policy version of this one; the no-login page covers what an anonymous run gets you; the Reel length limit page covers the ceiling that stops a long clip; and bulk transcribing Instagram Reels covers what changes when there is more than one file.