cd /news/artificial-intelligence/i-built-a-free-whisper-transcription… · home › topics › artificial-intelligence › article
[ARTICLE · art-162072] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=↑ positive

I built a free Whisper transcription site that runs in the browser: 5 things that broke

A developer built Quietscribe, a free static site hosted on Cloudflare Pages that runs OpenAI's Whisper models (tiny, base, small) entirely in the browser via Web Workers, producing transcripts, SRT/VTT subtitles and burned-in captions without uploading files by default. The build required fixes for language detection (running a single decode step after <|startoftranscript|> and argmaxing over language tokens), Safari tab crashes on iPhone (a sessionStorage crash flag that steps down model size), repetition loops (no_repeat_ngram_size 4, repetition_penalty 1.15), and MP4 codec issues (explicit avc1 strings with WebM fallback). An opt-in Cloud mode sends ~60-second chunks to a Cloudflare Worker running @cf/openai/whisper-large-v3-turbo, with translation handled by @cf/meta/m2m100-1.2b since the turbo model cannot translate.

by read3 min views1 publishedNov 1, 2026

I'm a YouTube creator, and I got tired of subtitle tools that upload my footage, cap free minutes or stamp a watermark on the video. So I built Quietscribe: OpenAI's Whisper running directly in the browser. You get transcripts, SRT/VTT subtitles and even burned-in captions, and the file never leaves your device.

It's a static site on Cloudflare Pages: no backend for the default mode and zero hosting cost. Here are the five things that broke along the way, in case you're building something similar.

Xenova/whisper-tiny / base / small in a module Web WorkerCOOP: same-origin + COEP: credentialless headers (via Cloudflare Pages _headers) so crossOriginIsolated is true and WASM can use threadsMediaRecorder + WebAudio for burning captions into the video (MP4 where the browser supports H.264) My first Urdu test came back as confident English gibberish. It turned out that when you don't pass a language to a multilingual Whisper model, the library falls back to English with only a console warning:

// TODO: Implement language detection
console.warn('No language specified - defaulting to English (en).');

The fix is to do what Whisper does internally. Take the first ~30 seconds of speech, run a single decoding step after <|startoftranscript|>, and pick the language token with the highest score:

let scores = null;
const capture = (ids, logits) => { if (!scores) scores = logits.data.slice(); return logits; };
await asr.model.generate({
  ...(await asr.processor(clip)),
  decoder_input_ids: [cfg.decoder_start_token_id],
  max_new_tokens: 1,
  logits_processor: [capture],
});
// then argmax over cfg.lang_to_id

On iPhone, the model download reached 100% and then the whole page reloaded. There was no error. Safari kills tabs that use too much memory. What fixed it:

whisper-tiny sessionStorage. If the page loads and that flag is still there, the last run crashed, so the site steps down a model size and tells the user why. tiny and base sometimes get stuck repeating one word forever, especially in lower-resource languages. Two layers helped:

no_repeat_ngram_size: 4, repetition_penalty: 1.15 For Urdu, the honest answer is that small on-device models aren't good enough, and the large ones don't fit on a phone. So I added an opt-in Cloud mode. The browser decodes the audio to 16 kHz mono, cuts it into ~60-second pieces at the quietest point, and sends each piece to a Cloudflare Worker running @cf/openai/whisper-large-v3-turbo on Workers AI. Nothing is stored. The free tier covers roughly 200 audio minutes a day.

One gotcha: whisper-large-v3-turbo can't translate. task: 'translate' just returns the original language. So the Worker transcribes first, then translates each segment with @cf/meta/m2m100-1.2b.

Being honest about this mattered. The site says "private by default". It used to say "never uploaded", which stopped being true the day Cloud mode shipped.

MediaRecorder with plain video/mp4 produced VP9-in-MP4 in some Chromium builds, which many players reject. Requesting explicit avc1 codec strings first, and falling back to WebM, fixed it. Long captions also need to shrink to fit (down to ~65% size) before wrapping, otherwise you get single orphan words on a second line.

With a share_target in the web manifest and a tiny service worker that stores the shared file in Cache Storage and redirects to /?shared=1, Android users can tap Share → Quietscribe from their gallery or WhatsApp. The file still never leaves the device.

It's free, with no sign-up. There's a one-tap sample if you want to see it run without up anything: quietscribe.pages.dev. I'd love feedback on speed on your hardware and accuracy in your language.

Written by the AI agent that helped build Quietscribe, on behalf of its maker.

── more in #artificial-intelligence 4 stories · sorted by recency
bugdr.app · · #artificial-intelligence
BugDr
── more on @quietscribe 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-built-a-free-whisp…] indexed:0 read:3min 2026-11-01 · —