Signal · signalsVersion 5

speech_voices

The installed speech synthesis voices (name, language, local, default), sorted and hashed. Nothing is spoken. Kept out of both ids because some browsers fill the list late.

speech_voices at a glance (from the library code, signalsVersion 5)
Component namespeech_voices
In the visitorIdno (reported, kept out of both ids)
structuredId groupnone
Hashingalways a digest, except the plain value none when nothing is found
Excluded underno browser class
Inner timeout1000 ms
Added insignalsVersion 1
In plain words

Computers and phones come with voices for reading text aloud, and which voices are installed depends on the operating system, its language packs and the browser. WhiskerJS asks the browser for that list and keeps a short hash of it. Nothing is ever spoken. Some browsers deliver the list late, so it is reported but kept out of the identifiers.

What it reads

speechSynthesis.getVoices(): for each voice its name, lang, localService and default flags.

How the technique works

  1. Without speechSynthesis.getVoices the component is unavailable / no_api.
  2. The list is read. If it is empty and the browser supports events, WhiskerJS listens for voiceschanged and waits up to 600 ms, whichever comes first, then reads the list again and removes the listener.
  3. Each voice becomes name|lang|local|default (the flags as 1 or 0); the entries are sorted and joined with ;.
  4. The value is always hashed; an empty list gives the plain value none.

Why it helps

Voice lists differ a lot between operating systems, system languages and browsers (some browsers add network voices of their own, marked not local). Two devices with the same screen and fonts can still differ here.

Your server can use it as context next to the stable ids, for example to see that two results with the same visitorId also have the same voices, or to notice a minimal environment with no voices at all.

Stability

Medium: some browsers fill the list only after a delay, so one run can see none and the next the full list. Installing a language pack or voice changes it too. That is why it is outside both ids.

Browser support and what blocks it

Most current browsers, including Chrome, Edge, Safari, iOS browsers and Firefox, have speechSynthesis. Headless and minimal builds often have no voices and report none. No browser class excludes it.

Privacy

Installed voices can hint at the system languages a user has added. WhiskerJS reports only a digest and produces no sound. Leave it out with collect({ exclude: ['speech_voices'] }) if you do not need it; no id changes.

How WhiskerJS handles noise and failures

Status ruleId When
ok a digest, or plain none
unavailable no_api no speechSynthesis.getVoices
unavailable no_digest a non-empty list without crypto.subtle
blocked threw, security_error reading the voices throws
excluded caller_excluded you excluded it
timed_out timeout, aborted budget or abort

The 600 ms wait sits inside the 1000 ms inner timeout.

Example value

In the container test, headless Chromium and Firefox reported none and headless WebKit reported the digest 89cde6c218596206e4119d0f5cf15c09.

Questions and answers

Does WhiskerJS make the browser speak?

No. It only calls speechSynthesis.getVoices() to read the list. No utterance is created and nothing is spoken.

Why is the list sometimes empty?

Some browsers load voices asynchronously. WhiskerJS waits up to 600 ms for the voiceschanged event; if the list is still empty it reports the plain value none.