Skip to content
All fingerprint checksClocks & ledgers

both generations of the navigation timing API describe the same page load

Check id navigation-timing-dual-api

What an ordinary browser yields

Every milestone reached on both APIs reconciles through timeOrigin to within a couple hundred milliseconds, and timeOrigin itself matches the legacy navigationStart.

What a detector infers

The platform kept two generations of one API alive. performance.timing speaks Unix epoch; PerformanceNavigationTiming speaks milliseconds since timeOrigin. Separate objects, separate code paths, the same eight moments in a page's life — and timeOrigin is the exchange rate between them. That redundancy is free ground truth: you can audit a browser's time origin without asking it for the origin, by solving for it from the pair. The lesson generalises well past clocks: whenever a platform ships a deprecated API beside its replacement, the two are a coherence oracle, because tooling that spoofs the modern surface almost never remembers the fossil underneath it. Three guards keep it honest. The deprecated interface's PRESENCE is a gate rather than an assertion, so the day Chrome finally removes performance.timing this check goes quiet instead of firing — its own rot makes it silent, never wrong. Any milestone reading zero on either side is skipped, because milestones read zero until reached and comparing a zero against timeOrigin plus zero manufactures a timeOrigin-sized error, which would be a guaranteed false critical on a page still loading. And a page activated from a prerender is excluded outright: it keeps timeOrigin at prerender start while the two APIs anchor differently by design, so any real site using speculation rules would trip a naive version.

How to resolve it

Both APIs record the same instants through different code paths, and timeOrigin converts between them. Anything rewriting the modern surface has to rewrite the fossil underneath it in lockstep — which is easier to achieve by not rewriting either.

How automation gets caught, layer by layer

Read in the wild by

PerimeterX / HUMAN

PerimeterX's collector records the presence of the legacy performance.timing object and whether the modern performance.getEntries is a function as two separate boolean fields in one payload, alongside performance.navigation.type — it probes both API generations for existence rather than reconciling their milestones against each other.

PerimeterX main.min.js as deployed on ifood (PerimeterX_RE corpus, stample/ifood/source/main.min.js; identical copy at node_bridge/ifood/perimeterx/main.min.js). `function Cn(t)` runs a vendor-prefix sweep over ["","ms","o","webkit","moz"] with `u=""===c?"performance":c+"Performance"`, and on each pass does `hS[u]&&(r=!!hS[u].timing,h=hR(hS[u].getEntries)===ie)` — hS is the global, hR is the Babel _typeof helper and `ie="function"`, so r is `!!performance.timing` and h is `typeof performance.getEntries === "function"`. The two are emitted as separate fields: `t["eEQNDj0jDzg="]=r` (legacy timing present) and `t[hQ(798)]=h` with hQ(798)="NSEAa3NBAFs=". `function Co(t)` adds `t[hQ(819)]=hS.performance&&hS[hQ(199)].navigation&&hS.performance[hQ(820)][hQ(821)]`, where hQ(199)="performance", hQ(819)="b19aVSo/XWc=", hQ(820)="navigation", hQ(821)="type". Indices resolved against bug_report/sdk_drift_cases/2026-05-19_ifood/hQ_map.json. Observed on the wire in a captured payload (bug_report/sdk_drift_cases/2026-05-19_ifood/diff_result.json), the three arriving adjacent: {"k":"NSEAa3NBAFs=","value":true}, {"k":"eEQNDj0jDzg=","value":true}, {"k":"b19aVSo/XWc=","value":1}; the navigation-type field also appears in stample/ifood/sample/{4,5,6}/decoded_payload_2.json with value 0.

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

Other checks in Clocks & ledgers

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 Clocks & ledgers 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 Clocks & ledgers — the family navigation-timing-dual-api belongs to.