Text-to-Speech Cheat Sheet
The browser-native Web Speech API reads text aloud with no backend and no cost. This page covers the core speech parameters, common SSML tags and the mobile/Safari compatibility pitfalls that make web reading sound natural and stable.
Core Speech Parameters
| Parameter | Meaning | Tuning Tip |
|---|---|---|
| rate | Speech rate; 1 is normal, roughly 0.1–10 | Chinese reads well at 0.9–1.1; English can go to 1.2 |
| pitch | Voice pitch; 1 is default, roughly 0–2 | A ±0.1 nudge distinguishes speakers; avoid extremes |
| volume | Volume; 1 is default, 0 is muted | Usually leave at default and defer to system volume |
| voice | Pick a specific speaker by language and gender | List with speechSynthesis.getVoices() and filter by lang |
| lang | Declares the text language, drives voice choice | For mixed zh/en, switch lang per sentence for naturalness |
Frequently Asked Questions
Does the browser have built-in TTS, or do I need a backend?
Modern browsers ship SpeechSynthesis from the Web Speech API, so you can read text entirely client-side with no backend call and no extra cost. The catch: available voices depend on the OS-installed voices, so timbre varies across devices.
Is SSML fully supported on the web?
Support is inconsistent. Desktop Chrome reasonably supports common tags like <break> and <prosody>, but mobile and Safari are spotty and silently ignore some tags. In production, feature-detect and fall back to plain-text reading where SSML is unsupported.
Why does getVoices() sometimes return empty?
The voice list loads asynchronously and may not be ready right at page open. Listen for the voiceschanged event, or only build the UI after a non-empty list arrives, otherwise you will not be able to pick a voice.
What if long-text reading gets cut off?
Some browsers cap a single utterance by length or duration and truncate the rest. Split by paragraph, chain segments on onend, and insert a <break> at boundaries so pauses feel natural.