Back to Blog

My Voice Left the Browser and Nobody Said So

September 9, 2026
Share:
My Voice Left the Browser and Nobody Said So

I wanted to dictate a paragraph without installing anything. Open a page and talk.

The first tool I tried worked. Then I paused to think and it stopped listening, silently, and I lost the sentence I was building. The second one wanted an account. The third one worked well enough that I kept using it for a week before I went and read what it was actually doing with my microphone.

It was sending my voice to Google. Not the page. My browser. And the page had not said a word about it.

That's how the web speech API works in most browsers, and it's fine as long as you know. Almost nobody tells you. So the dictation tool I shipped this week prints it, above the button, before you press anything.

The Pause That Killed the Session

Browser dictation ends by itself. You press start, say a sentence, stop to think about the next one, and the recogniser closes the session. If the page does nothing about that, the microphone is just off and nothing tells you.

I assumed there was a documented timeout I could design around. There isn't. I read the Web Speech API specification looking for the number and searched the whole document for "timeout" and "silence". Zero hits. The spec sets no silence threshold and no maximum session length. How long your browser keeps listening is entirely your browser's business.

What the spec does define is an end event that fires whenever the session ends, whatever the reason. That's the hook. A page that listens for it and starts a new session is doing the thing every usable dictation tool does, and a page that doesn't looks broken the first time you take a breath.


Where the Audio Actually Goes

Speech recognition in a browser is not one implementation. Each vendor built their own, they made different choices, and the API hides all of it behind the same handful of lines of JavaScript. You get identical code and four different privacy stories.

BrowserWhere your voice goesThe name it answers to
Chrome, desktopGoogle's speech serviceBoth names since Chrome 139
Chrome, AndroidThe phone's own recogniserBoth names since Chrome 139
EdgeMicrosoft's Azure serviceBoth names since Edge 139
SafariApple's system engine, on the device when a model exists for the languagePrefixed only
FirefoxNowhere, it's switched offBehind a preference

Every row of that table came from a primary source I read this week. The details underneath it are where the surprises are.


Chrome on the Desktop Uploads to Google

Chromium hard codes the upload target, and it points at a Google speech endpoint. It isn't a setting you can change or a fallback. That's the engine.

Mozilla's reference documentation says the same thing in plainer words, and says it about the default path for the API as a whole:

Your audio is sent to a web service for recognition processing, so it won't work offline.

That last clause is the tell you can check yourself. Turn off your network and press the dictation button. On desktop Chrome nothing comes back, because there's nothing on your machine doing the transcribing.


Chrome on Android Takes a Different Road

This one surprised me, and it's why the table has two Chrome rows.

The Google endpoint lives on the branch of Chromium that isn't Android. On a phone, Chrome hands the audio to the Android platform recogniser instead, through the operating system. Same JavaScript, different destination.

So "Chrome sends your audio to Google" is true on your laptop and sloppy on your phone. I wrote the sloppy version first, then went and read the branch and rewrote the line on the page. If you're going to make a privacy claim, make the narrow one you can actually point at.


Edge Says It Out Loud

Microsoft documents this better than anyone else, in the least likely place: the admin policy reference for the setting that turns speech recognition off across a fleet of managed browsers.

The page says the Edge implementation uses Azure Cognitive Services, so voice data leaves the machine. That's Microsoft's own sentence about their own browser, written for an IT administrator deciding whether to allow it. It's the clearest statement any vendor makes on this, and it's buried where a normal person will never see it.

Microsoft also has a local model in progress. As of their June documentation it's in the Canary and Dev channels only, behind a flag, covering six languages. Not in the browser your visitors have.


Safari Asks the Phone First

WebKit does something different again. Instead of shipping a speech backend, it hands the microphone to the same system speech framework the rest of your Mac or iPhone uses, and asks it to stay on the device whenever the operating system says it can for that language.

When the system has a local model for what you picked, your voice never leaves the hardware. When it doesn't, Apple's recogniser falls back to the network and the audio goes to Apple.

There's a catch worth knowing before you tell someone "just use Safari": it needs Siri turned on. Turn Siri off in system settings and the API isn't there.


Firefox Ships It Switched Off

Firefox has the code and keeps it disabled. The preference sits in Firefox's own default list set to false, so nothing happens on a normal install, and Firefox for Android doesn't have it at all.

That's why the page checks for the API on mount and, when it isn't there, says so in a plain sentence instead of leaving you clicking a dead button. A tool that fails silently in a whole browser is worse than a tool that says "not here, try Chrome or Safari".


The Spec Never Promised Local

It would be easy to read all of that as four vendors quietly breaking a promise. They aren't. There was never a promise.

The specification says the API is agnostic about the implementation underneath and supports both server based and embedded recognition. It's written that way deliberately. A browser sending your audio to a datacentre is doing exactly what the standard allows.

There is one attribute that forces the issue, and its default is the whole story: set it to true and recognition must happen locally, leave it alone and the browser is free to choose. It defaults to false. Every page that doesn't think about this gets the remote path, which is most pages.


Restarting, and the Loop That Eats a Microphone

So the fix for the pause problem is to restart in the end handler. That's four lines and it works.

It also has a failure mode that will pin a CPU and flash a microphone indicator forever. If the microphone is blocked, or missing, or the browser refused permission, the session doesn't pause. It ends immediately, every time, as fast as you can start it. Restart without thinking and you've written a spin loop with a permission prompt in it.

The page counts restarts since the last time speech actually came through. Eight of them inside five seconds means this isn't a person pausing, it's a microphone that isn't coming back, so it stops and says to check the microphone. Every real pause resets the counter to zero, so a long dictation never trips it.

That rule lives in a pure function with its own tests, away from the browser API, which is the only reason I trust it. You cannot test "the microphone is broken" by hand eight times in five seconds.


The Error Codes Are the Documentation

The API reports failure through a small set of codes, and they're more useful than they look. Mozilla lists nine. What matters for a dictation page is which of them are worth retrying.

CodeWhat happenedWhat the page does
no-speechNothing was picked upRestarts quietly, this is a normal pause
networkThe speech service was unreachableSays dictation needs a connection
not-allowedThe browser refused the microphoneStops and tells you to allow it
audio-captureNo microphone foundStops, retrying won't find one
language-not-supportedYour browser doesn't have that languageStops, asks for another language

The split is the design. Four of those five mean the next start will fail exactly the same way, so retrying is just noise with a permission prompt attached. One of them is what a thoughtful pause looks like from the outside.

There's a tenth thing the spec says about errors that I'd have got wrong on my own: the event carries a human readable message, and the spec explicitly says not to show it to users. It's for you, in the console. What the reader gets is a sentence you wrote.


You Cannot Ask Which Languages Work

The picker on the page offers 38 languages. I would like to offer exactly the ones your browser can actually do, and I can't, and neither can anyone else.

Mozilla states it plainly: there's no way to determine from front end code which languages a browser supports for speech recognition. The set is browser dependent and there's no method to ask.

So the picker is a reasonable list, and if you choose something your browser doesn't have, you get an error naming the reason. At least it fails out loud instead of quietly. It's still a gap in the platform, and I would rather say so than pretend the list is verified.


The On-Device Path Exists, With a Catch

Chrome 139 added a way to keep the audio and the transcript off a third party service, using a local model on the machine. Google's release note describes it in those terms.

Two catches. It's desktop only, so it isn't there on the phone where dictation is most useful. And each language needs a pack downloaded to the machine first, so asking for local processing without the pack fails rather than falling back.

That makes it a real feature with real setup, not a checkbox. The page doesn't ask for it today. When it does, it will be a visible choice with a download attached, and the sentence at the top will change to match. Printing "your voice never leaves your device" on the strength of a mode I haven't shipped would be exactly the kind of claim this post is complaining about.


What the Page Says Before You Press Anything

Most tools here can say the easy thing, because it's true: nothing leaves your browser. The merge tool stitches PDFs in the tab. The password generator makes the password in the tab and never transmits it.

This one can't say that, so it says the real thing instead, above the button, before you talk: which browser sends your audio where, and that none of it comes to us. We never receive the audio and we never store the text. What you say sits in a box on the page until you copy it, download it, or close the tab.

That's the whole reason this post exists. Copying "nothing leaves your browser" onto a page that uploads your voice would have been faster and nobody would have caught it.


What You Get

Press the button and talk. Words appear as you say them, with the current guess showing underneath until the recogniser commits to it.

The box is an ordinary text box, so you fix a name or delete a false start by typing, and keep going. Say "comma", "period" and "new paragraph" and most engines will place them for you.

Copy takes the text. Download writes a .txt. Turn timestamps on first and the file gets a stamped line for each thing you said, which is what you want for notes against a meeting.

You don't need an account, and there's no cap on how long you talk.


What To Do With It

  1. Open it in Chrome or Safari. Firefox will tell you it's off, and that's the browser, not the page.
  2. Read the line above the button once. It's four sentences and it's the only part of this you can't undo later.
  3. Press start and talk in whole sentences. Half a phrase gets guessed at more than a finished one, because recognition uses the words around a word to choose it.
  4. Fix it in the box, then copy or download. If you're taking notes, turn on timestamps before you download.
  5. If it's a long piece, run it through the word and character counter to see whether it fits wherever it's going, and the em dash remover to clean up punctuation the engine guessed at.

It's the twenty-fifth free tool on the site, and the first one where the honest privacy paragraph was harder to write than the code.


Last updated: September 9, 2026 | Reading time: 10 minutes

Written by Evgeniy Poznyak, who read a lot more browser source code than he meant to for one short paragraph.