Why text-to-speech voices differ by device

The same text sounds different on a Mac, Windows, Android or in Chrome. Where browser voices come from, which ones go online, and how to get Vietnamese.

On this page

Paste the same paragraph into a text-to-speech page on two computers and you can get two different voices, two different lists of languages, and on one of them perhaps no Vietnamese at all. That is not a bug in the page. Websites that read text aloud in the browser use the Web Speech API, and that API does not come with voices of its own: it asks the device. This article explains where the voices come from, what "online" voices mean for privacy, why highlighting and long texts behave differently from one voice to another, and how to add a missing language. Everything here applies to the text to speech tool on this site.

The browser lends the page its voices

In the Web Speech API, a page calls speechSynthesis.getVoices() and gets a list of voices, each with a name, a language tag such as vi-VN, and a few flags. The specification says this list may be empty when "the list of available voices is not yet known", and that the browser fires a voiceschanged event when it changes. Chrome in particular fills it in a moment after the page loads, which is why a tool that reads the list only once may show nothing. The text-to-speech tool listens for that event and fills its menu when the voices arrive.

Where do the voices come from?

  • macOS and iOS offer a long list of system voices, including Vietnamese, and many better-quality voices that must be downloaded first in the Spoken Content section of the Accessibility settings.
  • Windows has a few voices built in and more in optional speech packs, added under Time and language, then Speech, in Settings.
  • Chrome on a computer adds its own set of voices named "Google …", which are synthesised online.
  • Edge adds Microsoft voices named "… Online (Natural)", which are also synthesised online.
  • Android uses whichever text-to-speech engine is installed and its downloaded languages.

So "Samantha" on a Mac, "Microsoft Zira" on Windows and "Google US English" in Chrome are three different engines that happen to read the same words.

On-device or online: the localService flag

Each voice has a localService flag. MDN describes it as true when the voice is supplied by a local synthesizer and false when it comes from a remote service, and notes that remote voices may bring extra latency, bandwidth or cost. A remote voice means the text is sent to that service to be turned into sound. The specification adds that the flag promises nothing about quality or price.

The tool shows this in the voice list as on device or online. For a contract, a medical note or anything private, choose an on-device voice; the text then never leaves the computer or phone.

Highlighting the spoken word

While speaking, a voice can fire boundary events at word and sentence boundaries, each with a charIndex: the position in the text where the word begins. The specification says that when the engine cannot provide the position, the value is 0. MDN also marks the boundary event as having limited availability. In practice, many on-device voices report each word, while some online voices report nothing useful, and then no highlighting is possible. The tool tells you when that happens instead of highlighting the wrong word.

One detail matters for Vietnamese. charIndex counts UTF-16 code units, not letters. "Việt" typed with precomposed letters is 4 units long, but the same word in decomposed form (e, then a dot below, then a circumflex as separate combining marks) is 6. The tool finds the whole word around the reported position, combining marks included, so the highlight lands on "Việt" either way. In "Xin chào, Việt Nam!" a boundary at index 10 highlights characters 10 to 14: Việt.

Long texts and the stopping voice

The specification allows an engine to limit the length of one utterance and gives 32,767 characters as an example. Real engines can fail much sooner. Compatibility notes for Chrome report that playback stops after about 15 seconds on some platforms, and developers have traced long-text stalls to Chrome's online Google voices: the API says it is still speaking, but nothing is heard.

The common fix is to hand the engine short pieces. The tool cuts text into chunks of at most 220 characters, breaking at the end of a sentence when it can. A 396-character paragraph of four sentences of 43, 56, 132 and 165 characters becomes three chunks: the first two sentences together (99 characters), then 132, then 165. The first two fit together; adding the third would make 231 characters, over the limit, so it starts a new chunk. Each chunk keeps its position in the original text, so highlighting stays correct.

Why you cannot download the audio

The browser plays synthesised speech straight to the speakers. The Web Speech API gives the page no access to that audio, so no site using it can offer an honest "save as MP3". Sites with a download button synthesise on their own servers, which means your text is uploaded to them. If you need a file, record your own reading with the voice recorder and trim it with the audio trimmer.

Common mistakes

  1. Assuming a missing language means the site does not support it. The device lacks the voice. Install it in the system settings and reload the page.
  2. Reading private text with an online voice. Pick a voice marked on device.
  3. Reading Vietnamese with an English voice. Numbers, dates and abbreviations follow the voice's language: "1.000" means one thousand in Vietnamese but one in English.
  4. Pasting a whole chapter into a tool that sends it as one utterance. Some voices stop silently; chunking avoids it.
  5. Reading the voice list once at load. It may still be empty; wait for voiceschanged.

Try it

Open the text to speech tool, paste your text, pick a language and a voice and press Read aloud. To clean up line breaks that make a voice pause in odd places, run the text through the text toolkit first.

Tools mentioned in this article

Back to the blog