navigator.productSub === 20030107 (Chromium)
Check id product-sub
What an ordinary browser yields
A Chrome UA with productSub === "20030107", or a non-Chrome UA (check reports N/A).
What a detector infers
navigator.productSub is a frozen legacy constant, not a live value: Chrome, Safari and Opera return "20030107" while Firefox returns "20100101". The check reads it and, only when the UA carries a Chrome/ token, requires "20030107"; on a non-Chrome UA it returns N/A and is not scored. Like the eval-length probe, it is gated on the claimed identity rather than on an engine sniff, so it catches a Gecko engine behind a Chrome UA without depending on window.chrome existing. A detector reading it is asking the engine to identify itself through a channel most spoof layers never enumerate, because the property looks inert. Severity is warn rather than critical — it is a corroborating engine-family signal that lands alongside stronger ones.
How to resolve it
Match the UA to the real engine family. If a Chrome UA is reporting Firefox's 20100101, the underlying engine is Gecko and the fix is the engine choice, not the property — patching this one constant leaves every sibling engine tell intact.
Read in the wild by
PerimeterX / HUMAN
Ships navigator.productSub verbatim to its telemetry endpoint, in the same navigator-collection routine as navigator.product, appName, appCodeName, appVersion and the Firefox-only navigator.buildID — and PX's own shipped string table annotates it "productSub (important returns the build number of the current browser)".
PerimeterX main.min.js (iFood tenant build, PerimeterX_RE/stample/ifood/source/main.min.js), where `hU=navigator`: `t[0][hQ(853)]=hU[hQ(854)]` with hQ(853)="JnZTfGAaUUY=" and hQ(854)='productSub' → decoded EV2 field "JnZTfGAaUUY=" = "20030107" (unhashed) across all six captured payloads. Siblings in the same routine: `t[0][hQ(851)]=hU[hQ(852)]` (hQ(852)='product') → "DFg5Ekk9MyE=" = "Gecko"; `t[0]["NkZDDHArQz8="]=hU.appName` → "Netscape"; `t[0][hQ(858)]=hU[hQ(859)]` (hQ(859)='buildID'); `t[0][hQ(860)]=hU[hQ(653)]` (hQ(653)='appCodeName') → "X08qRRkuL34=" = "Mozilla". Reproduced under different obfuscation alphabets in the Walmart build (`e["LnVVdGgSWU4="]=eO.productSub`) and TotalWine build (`i[im(855)]=ir.productSub`). PX-authored annotations surviving in the shipped string tables: "productSub (important returns the build number of the current browser)" (Walmart) and "buildID (important return the buildID on firefox in addition to productSub)" (iFood).
Every attribution traces to a published artifact. See the sources and their limits.
Nearby checks in Navigator identity
- every brand in a UA-CH list uses the same version format
uach-brand-version-arityUA-CH publishes the same brand set twice at two precisions. navigator.userAgentData.brands carries bare majors like "148", and the… - navigator.language === languages[0]
languages-coherenceIn a real browser navigator.language is defined as the first element of navigator.languages — one preference list, two views onto it. - the host voice roster represents the language the browser claims
locale-vs-voice-coherenceThe voice roster is installed at the operating-system level and the language preference is set in the browser, so the two are genuinely… - eval.toString().length matches the engine (V8 = 33)
etslThe string a JS engine returns for a native function's source is an implementation detail, and its length differs per engine… - a Firefox user-agent reports the Gecko productSub constant 20100101
gecko-productsub-hardcodenavigator.productSub is a constant compiled into the engine, and the two families disagree: every Gecko build hardcodes it to "20100101"… - navigator.deviceMemory is a power-of-two spec value
device-memory-boundsnavigator.deviceMemory does not report actual RAM — the spec requires the UA to quantise it to a coarse power-of-two rung before exposing… - navigator.hardwareConcurrency is plausible
hardware-concurrencyThis is an info-severity observation, not a scored failure — it reports navigator.hardwareConcurrency and only notes whether the value is an… - the machine delivers no more parallelism than it claims cores
hardware-concurrency-vs-parallelismThe plain hardwareConcurrency row can only ask whether the number looks sane, because no second API reports a core count.
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 product-sub belongs to.