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.

How It Works

Text-to-speech (TTS) synthesizes speakable audio from text. Two implementations: the browser-built Web Speech API (SpeechSynthesis — zero-dependency and instant, but voice quality is limited by the OS/engine), and cloud TTS services (vendor APIs with more natural voices, multi-language support and SSML tuning).

SSML (Speech Synthesis Markup Language) uses XML to describe pauses, intonation and speaker details for more natural reading. Output is usually MP3/WAV/OGG audio; sample rate and bitrate trade size against clarity, and front-end real-time reading often streams chunks to cut latency.

Core Speech Parameters

ParameterMeaningTuning Tip
rateSpeech rate; 1 is normal, roughly 0.1–10Chinese reads well at 0.9–1.1; English can go to 1.2
pitchVoice pitch; 1 is default, roughly 0–2A ±0.1 nudge distinguishes speakers; avoid extremes
volumeVolume; 1 is default, 0 is mutedUsually leave at default and defer to system volume
voicePick a specific speaker by language and genderList with speechSynthesis.getVoices() and filter by lang
langDeclares the text language, drives voice choiceFor 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.