Skip to content
All fingerprint checksNavigator identity

navigator.appVersion is the user agent minus its leading token

Check id appversion-vs-useragent

What an ordinary browser yields

On Blink and WebKit, appVersion is byte-for-byte the user agent minus its leading "Mozilla/". On Gecko the check reports N/A, because that engine does not mirror the UA there.

What a detector infers

navigator.appVersion is not an independent fact. In Blink and WebKit it is computed from the User-Agent at read time — literally the UA with everything up to the first slash removed — so it is the same sentence with eight characters missing. Overriding navigator.userAgent from page script replaces one reader and leaves the other quoting the original build, which is why a spoofed UA is so often betrayed by the property nobody remembers exists. PerimeterX collects both readers in one payload, next to productSub, platform and the rest of the NavigatorID surface, and lets the pair speak for itself. The check goes quiet on the entire Gecko family, and that restraint is the interesting part: Firefox deliberately answers a truncated form like "5.0 (Windows)" and does not mirror the UA at all, so there is nothing to compare and the honest move is silence. That includes Firefox with a UA override or a UA-switcher addon — the check simply has no power there, which is the price of not false-positiving. It was nearly built the looser way, asserting that appVersion's platform token must prefix the UA's; browser testing killed that variant, because Firefox for Android in desktop mode serves a Linux user agent while appVersion keeps saying Android, and one tap on an ordinary phone would have thrown a critical.

How to resolve it

Set the user agent at launch, or through the browser's own override, so every reader derives from one source. Assigning navigator.userAgent moves one reader and leaves appVersion — computed from the real UA when you read it — quoting the build underneath. A Chrome-family UA-switcher extension produces exactly this shape, so seeing it here does not necessarily mean automation; it means two readers of one fact disagree.

Coherence over camouflage: why a plausible identity beats a hidden one

Read in the wild by

Kasada

Kasada's fingerprinting script reads navigator.appVersion and navigator.userAgent into separate slots of its payload, and collects the pair twice — once from the page's own window and once from an iframe's contentWindow.

blog.txt:666-684 (emro.cat Kasada ips.js teardown, solver output "mapped: 427/427 probes") assigns four distinct payload slots: "124:window_navigator_app_version(fn_129709)", "171:window_navigator_user_agent(fn_177174)", "263:iframe_navigator_app_version(fn_9673)", "146:iframe_navigator_user_agent(fn_169577)". Corroborated in the decompiled IR (1.txt), where each is a probe function reading off one of two realm handles: 1.txt:1296-1297 "r5 = a0.lrc; r5 = r5.navigator.appVersion;"; 1.txt:37347-37348 "r5 = a0.lrc; r5 = r5.navigator.userAgent;"; 1.txt:45469 "r4 = r4.kcm.navigator.appVersion;"; 1.txt:47972-47973 "r4 = r4.kcm.navigator; return r4.userAgent;". The lrc/kcm handles are the batch-context realm pair built at 1.txt:24390-24394 "r4 = { lrc: _882, kcm: r6 };" beside "_912.contentWindow"; blog.txt documents the structure as a batch context storing "a reference to window under .exg and a reference to an iframe's contentWindow under .ukz". (probes.txt lines 164/167/391/394 list the same four names, but is a derived index of this solver output.)

PerimeterX / HUMAN

Collects navigator.appVersion and navigator.userAgent as two separate fields in the same payload, alongside product, productSub, appName and platform, and ships both raw — a deployed collector sends the user agent and the user agent minus its leading "Mozilla/" as independent values.

PerimeterX main.min.js on ifood.com.br: `t[0][hQ(855)]=hU[hQ(856)]` with hQ(855)="PSkIY3hPC1U=" and hQ(856)='appVersion', a few statements from `t[0]["RBBxWgJydmw="]=hU[hQ(845)]` with hQ(845)='userAgent' — in the same `t[0]` collection block as `t[0][hQ(851)]=hU[hQ(852)]` (product), `t[0][hQ(853)]=hU[hQ(854)]` (productSub), `t[0]["NkZDDHArQz8="]=hU.appName` and `t[0][hQ(844)]=hU.platform`. Decoded EV2 payload carries both keys in one object: "PSkIY3hPC1U=" = "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36" beside "RBBxWgJydmw=" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36".

Every attribution traces to a published artifact. See the sources and their limits.

Nearby checks in Navigator identity

See all 26 checks in Navigator identity
Who builds this test

Clearcote is a browser built for fingerprint coherence

It is a Chromium fork, maintained by the same people who wrote this reference. It ships as a compiled browser rather than as a stealth script injected into someone else's — which is a description of how it is built, and is not an argument about how it behaves on this check.

This audit takes no position on how Clearcote scores on Navigator identity checks, on this one, or anywhere else. It has no baseline corpus of other people's fingerprints to rank you against and no vendor scoreboard — nearly every check is self-referential, asking one browser the same question through two independent APIs and reporting whether both answers can be true at once. It runs identically on any browser, including ours. Run it on yours and read the result yourself.

See the other checks in Navigator identity — the family appversion-vs-useragent belongs to.