Skip to the tool
CaptionSuiteCaptionSuite home

Guides

How Whisper runs in a browser tab

Updated

Whisper is OpenAI's speech recognition model, and a browser can run it because three pieces now exist: transformers.js to drive the model, ONNX Runtime to execute it, and WebGPU to put that execution on your graphics card. The weights are downloaded once and cached, the audio never leaves the page, and the speed depends entirely on which backend your browser offers. On WebGPU it runs several times faster than realtime. Without it, it runs on the CPU, and nobody here has measured how slow that is.

The three pieces

None of this is a single browser feature. It is several independent things that happen to compose, and knowing which is which makes the failures legible when one of them is missing.

  • transformers.js, which loads the model, turns audio into features and runs the decoding loop
  • ONNX Runtime Web, which actually executes the network, either on the GPU through WebGPU or on the CPU through WebAssembly
  • WebGPU, the browser interface to your graphics card. Present in recent Chrome and Edge, newer Safari, and behind a flag or absent elsewhere
  • Cache Storage, which keeps the downloaded weights so the second run starts instantly
  • A Web Worker, so none of this runs on the thread that draws the page. A model on the main thread would freeze the tab for the whole job

The model is a download, not an upload

This is worth being precise about, because it is the one thing that crosses the network and it is easy to mistake for the opposite.

The weights are fetched from a CDN the first time you transcribe: 45MB for the faster model, 80MB for the more accurate one. That traffic comes towards you. Your recording is read from disk by the page and handed to the worker as raw audio samples, and there is no code path that sends it anywhere, because there is no server behind this site to send it to.

You do not have to take that on trust. Open the network tab, transcribe something and sort by size: the model files are the only large transfer, and there is no large request going out. The stronger version of the test is to disconnect from the network once the model has cached. Transcription still works.

WebGPU against the fallback, and why the gap is large

With WebGPU, the arithmetic runs across hundreds of GPU cores at once. The measured figure is 8.6x faster than realtime on a 31-minute recorded lecture, Chrome, 16GB Windows laptop, using whisper-base on 2026-09-26.

Without it, the same model runs through WebAssembly on the CPU, and on this site it runs single-threaded. That is a consequence of a header setting rather than a limit of the technology: multi-threaded WebAssembly needs SharedArrayBuffer, browsers only grant that to cross-origin isolated pages, and cross-origin isolation would block the model download from the CDN unless a mode Safari does not yet support is used. The tradeoff was made deliberately in favour of the download working everywhere.

So the honest statement is that the published speed is a WebGPU figure and the CPU path is unmeasured. If your browser reports no WebGPU, expect a wait of a different order, and start with a short file to find out what you are dealing with before committing an hour of audio to it.

Why it transcribes in 90-second windows

Whisper processes 30 seconds of audio at a time by design, and the usual approach is to hand the whole file to the library and let it loop internally. That is not what happens here, for a reason that is about the experience rather than the accuracy.

The library's speech pipeline has no progress callback. Its chunk loop is sequential and silent, so one call over a long file means minutes with nothing to report and no way to cancel. For a tool whose main risk is looking broken while it is working perfectly, that is the wrong failure to accept.

So the worker does its own windowing: 90 seconds at a time, with a 12-second overlap between windows. The overlap is what stops a sentence being cut in half at a boundary, and the seam between windows is where progress is reported, where partial text appears, and where a cancel takes effect. The progress bar counts audio seconds actually processed, which is why it is a measurement rather than an animation.

What you give up against a hosted model

Size. The large Whisper builds run to gigabytes and are not going to download into a browser tab, so what runs here is one of the small ones. That costs accuracy on accents, crosstalk and technical vocabulary.

Speaker labels from Whisper itself. Separating who said what is a second model doing a different job, so when you switch identification on, two more models (pyannote segmentation and WeSpeaker embeddings) run after Whisper in the same worker and suggest the labels.

Confidence scores. The library's pipeline returns text and timestamps with no token probabilities, so there is no way to highlight the lines the model was unsure about. The editor compensates by flagging what is mechanically checkable instead: timing, overlap, reading speed, and stretches where the decoder has got stuck repeating itself.

Length. Everything has to fit in the tab alongside the model, which puts a ceiling of 2 hours on a single recording. That is a memory limit rather than a policy, and it is checked before you start rather than discovered halfway through.