| Component name | ua_versions |
|---|---|
| In the visitorId | no (reported, kept out of both ids) |
| structuredId group | none |
| 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 2 |
Chromium-based browsers can tell a page their exact version numbers and the operating system version. That is useful for your server, for example to spot an outdated browser or a mismatch with the request headers, but it changes with every update. WhiskerJS reports it separately and never lets it touch the identifiers.
What it reads
From navigator.userAgentData: fullVersionList and platformVersion from the shared getHighEntropyValues() call, or the low-entropy brands list when the detailed call gives nothing.
How the technique works
- Without
navigator.userAgentDatathe component isunavailable/no_api. - It uses the same single high-entropy request as
ua_client_hints. - Brands are filtered for GREASE and sorted. When
fullVersionListis present and not empty it is used; otherwise the low-entropybrands, whose versions are major versions only. - The value is
brands=Name/version,...;platform_version=<v>when the detailed hints came back, orbrands=...;he=<state>when they were blocked (he=blocked), failed (he=failed) or do not exist (he=none). - Longer than 128 characters means it is hashed.
Why it helps
Exact versions are a strong consistency check against the user agent header and the ua_client_hints brands, and they show outdated or unusual builds. They also explain id changes: if the browser group moved and ua_versions moved too, a browser update is the likely cause.
Keep it with the stored result so you can explain id changes later: when you see a new visitorId for a known account, an older and a newer ua_versions side by side often answer the question in seconds.
Stability
Low by design: it changes with every browser or operating system update. That is the reason it is outside both ids.
Browser support and what blocks it
- Chromium-based browsers: Chrome desktop, Chrome Android, Edge, Brave, Samsung Internet.
- Safari, iOS browsers and Firefox:
unavailable/no_api. - A Permissions Policy that refuses the detailed hints gives
he=blocked.
Privacy
Version numbers are shared by everyone on the same release, so they identify a release rather than a person. Your server already receives similar information in the user agent header. The value is not in an id.
How WhiskerJS handles noise and failures
| Status | ruleId | When |
|---|---|---|
ok |
versions, or a he= marker |
|
unavailable |
no_api |
no navigator.userAgentData |
unavailable |
no_digest |
a long value needs hashing without crypto.subtle |
excluded |
caller_excluded |
you excluded it |
timed_out |
timeout, aborted |
the hints did not answer in 1000 ms, or budget or abort |
Example value
From headless Chromium in a Linux container: brands=Chromium/140.0.7339.16,HeadlessChrome/140.0.7339.16;platform_version=7.0.14. Firefox and WebKit in the same run: unavailable / no_api.
Questions and answers
Why are versions kept out of the visitorId?
Browsers update every few weeks and operating systems often. With versions in the id, every update would give the same device a new id.
What do I get when the detailed hints are refused?
The brand list falls back to the low-entropy brands with their major versions only, and the second part becomes he=blocked (or he=failed, he=none) instead of platform_version.
Why is ua_versions sometimes a digest?
Any value longer than 128 characters is hashed. A long brand list with full versions can pass that limit.