Speech synthesis works everywhere with the operating system's voices. Recognition is Chromium 4,389 's SpeechRecognition (unprefixed since 139) or Safari 10 's webkitSpeechRecognition. Chrome 1 's default recognizer sends audio to a web service and fails offline; processLocally = true keeps it on the device after SpeechRecognition.install().
const rec = new (window.SpeechRecognition ?? window.webkitSpeechRecognition)();
Object.assign(rec, { lang: 'en-US', interimResults: true }); // words appear while you speak
rec.onresult = (e) => (out.textContent = [...e.results].map((r) => r[0].transcript).join(''));
listenButton.onclick = () => rec.start(); // prompts for the microphone
const local = await rec.constructor.available?.({ langs: ['en-US'], processLocally: true });
speakButton.onclick = () => {
const voices = speechSynthesis.getVoices().filter((v) => v.lang === 'en-US'); // loads async
const utterance = new SpeechSynthesisUtterance(`You said: ${out.textContent}`);
speechSynthesis.speak(Object.assign(utterance, { voice: voices[0], rate: 1.2 }));
};In headless Chrome 152 on Windows, available() returned 'downloadable' (a language pack can be installed) and the voices were Microsoft David, Mark and Zira. Grammars (SpeechGrammarList) were removed from the specification and do nothing; bias recognition toward names and jargon with rec.phrases.