# languages

> The browser's preferred languages in order, such as en-US,en.

Source: https://whiskerjs.com/signals/languages/ (last updated 2026-10-26)

**languages at a glance (from the library code, signalsVersion 9)**

| Field | Value |
| --- | --- |
| Component name | `languages` |
| In the visitorId | yes |
| structuredId group | [locale](https://whiskerjs.com/docs/identifiers/#structuredid) |
| Hashing | plain value; a digest only when longer than 128 characters or not printable ASCII |
| Excluded under | no browser class |
| Inner timeout | 1000 ms |
| Added in | [signalsVersion 1](https://whiskerjs.com/whats-new/) |

> **In plain words:**
>
> Browsers keep a list of the languages a person prefers, in order, for example English (United States) first, then English. Websites use it to pick a language. WhiskerJS reads that list as it is. Many people have only one or two languages, but the exact list and its order still separate groups of users.

## What it reads

`navigator.languages`, the string entries joined with commas. If the list is missing or empty, `navigator.language` alone. An empty result is `unavailable` / `no_api`.

## How the technique works

The list reflects the browser’s language settings, which by default follow the operating system’s languages and region. Joining the entries in order keeps both the choice and the priority. Values are short ASCII language tags in practice, so they are reported as plain text; a value longer than 128 characters or outside printable ASCII would be hashed.

## Why it helps

Language lists differ between regions and between people who add languages, and the order matters. It is in the `locale` group together with [`time_zone`](https://whiskerjs.com/signals/time-zone/) and [`intl_locale`](https://whiskerjs.com/signals/intl-locale/). It is also a strong consistency check against the request’s `Accept-Language` header; see [Recommended server checks](https://whiskerjs.com/docs/integration/#recommended-server-checks).

## Stability

It changes when the user adds, removes or reorders languages in the browser or the operating system. A change of only the `locale` part of the structuredId often has this cause.

## Browser support and what blocks it

`ok` in all browsers; not in the exclusion table. Some privacy modes report a reduced list (for example only the first language); WhiskerJS reports whatever the browser gives.

Integrity checks that look at the same properties: [`iframe_mismatch`](https://whiskerjs.com/docs/integrity/#iframe_mismatch) (`language` and `languages` against a clean frame), [`navigator_own_property`](https://whiskerjs.com/docs/integrity/#navigator_own_property) and [`native_tampering`](https://whiskerjs.com/docs/integrity/#native_tampering) (the `languages` getter).

## Privacy

It reveals language preferences, which can hint at origin or region. Read without permission or prompt, never sent by WhiskerJS.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` | none | for example `en-US,en` |
| `unavailable` | `no_api` | no languages and no language |
| `unavailable` | `no_digest` | a long or non-ASCII value needed hashing without Web Crypto |
| `blocked` | `security_error`, `threw` | the getter threw |
| `excluded` | `caller_excluded` | your `exclude` list |
| `timed_out` | `timeout`, `aborted` | 1000 ms inner timeout, budget, abort |

## Example value

```json
"languages": { "status": "ok", "value": "en-US,en", "hashed": false }
```

## Questions and answers

### Is languages the same as the Accept-Language header?

They come from the same browser setting and usually match. Comparing them on your server is a useful check; a mismatch can point to a script that changed one but not the other.

### Why did my headless browser report en-US@posix?

Headless browsers take the language from the operating system environment. In the container test run used for these pages, headless Chromium inherited a POSIX locale and reported en-US@posix.

## Related pages

- [intl_locale](https://whiskerjs.com/signals/intl-locale/): The resolved Intl locale and formats.
- [time_zone](https://whiskerjs.com/signals/time-zone/): The other main locale setting.
- [iframe_mismatch flag](https://whiskerjs.com/docs/integrity/#iframe_mismatch): Compares language and languages with a clean frame.
- [navigator_own_property flag](https://whiskerjs.com/docs/integrity/#navigator_own_property): Catches overrides of languages.
