Skip to content
All fingerprint checksEngine & OS oracles

Math.tanh rounds the way the claimed OS's libm rounds

Check id math-tanh-os-vs-ua

What an ordinary browser yields

The last bit of Math.tanh matches the libm of the operating system the user agent claims — a browser saying Windows rounds the way UCRT rounds.

What a detector infers

IEEE 754 fixes how a double is stored but does not require transcendental functions to be correctly rounded, so every operating system's C math library ships its own polynomial approximation and they disagree in the final bit — the two largest implementations differ on roughly a quarter of all inputs, usually by one unit in the last place. For years this was invisible from JavaScript because V8 bundled its own copy of fdlibm and therefore computed the same answer everywhere. That changed in Chrome 148: V8 swapped Math.tanh to std::tanh, which calls straight through to whatever libm the browser is linked against — glibc on Linux, libsystem_m on macOS, UCRT on Windows. The check evaluates tanh at 0.7, 0.8 and 0.9 and requires all three to match one platform's measured constants; tanh(0.8) separates all three operating systems in a single call, and the other two corroborate it. tanh(0.5) is deliberately excluded because it is identical everywhere and carries no information. What makes this among the strongest signals available is where the answer comes from. It is not a value the browser reports about itself — it is arithmetic performed by a C library underneath the JavaScript engine, so no navigator override, no CDP patch, no UA-CH shim and no launch flag reaches it. A headless Chrome on a Linux server presenting a Windows user agent is contradicted by its own floating point. Note also what the check refuses to do: an unrecognised set of constants — musl, a BSD libc, Apple Silicon's vector routines — reports nothing rather than guessing, and Math.tanh is the only Math function worth reading this way, since every other one still routes through bundled llvm-libc and is byte-identical across platforms. Technique documented by Scrapfly; the constants were verified against a real Windows Chrome 148 before shipping.

How to resolve it

There is no JavaScript fix, and that is the point: since Chrome 148 this value is produced by the C library the browser links against, below anything a page, an extension or CDP can reach. Either run the browser on the OS it claims, or claim the OS it is actually running on — the arithmetic will keep disagreeing no matter what userAgent, userAgentData and navigator.platform are set to. The check reports N/A rather than a failure on Chrome 147 and earlier, where tanh is still bundled fdlibm, and on Android, ChromeOS and iOS, whose libm this check has no measured signature for. It also declines when a desktop UA arrives on touch-primary hardware: Chrome for Android's Request-desktop-site rewrites the UA to the Linux desktop string, which would otherwise defeat the Android decline and adjudicate Bionic's arithmetic against a table holding only glibc, libsystem_m and UCRT.

Anatomy of a browser fingerprint: every signal, and why they must agree

Read in the wild by

Scrapfly

Published the technique: V8 commit c1486295ae5 (Chrome 148) swapped Math.tanh to std::tanh, routing it through the host libm, so the last bit of tanh names the operating system. Their table was re-verified here against a real Windows Chrome 148 before shipping.

Math.tanh(0.8): 0.6640367702678491 Linux/glibc · 0.664036770267849 macOS/libsystem_m · 0.6640367702678489 Windows/UCRT

Scrapfly — Math-based OS fingerprinting

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

Other checks in Engine & OS oracles

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 Engine & OS oracles 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 Engine & OS oracles — the family math-tanh-os-vs-ua belongs to.