Skip to content
All fingerprint checksEnvironment & locale

IANA zone offset matches the JS clock offset (incl. across DST)

Check id timezone-offset-coherence

What an ordinary browser yields

Both paths report the same minute offset for the resolved zone, e.g. 'IANA Europe/Amsterdam and Date both = 120min'.

What a detector infers

This is a two-source cross-check on the same fact. It takes the resolved IANA zone, formats the current instant through `Intl.DateTimeFormat` with that timeZone, reconstructs the wall-clock time as a UTC timestamp, and derives the implied offset in minutes. It then compares that against `-new Date().getTimezoneOffset()`, allowing 1 minute of slack for the second boundary. Intl and Date read the timezone through different internal paths, so a spoof applied to only one of them produces two numbers that disagree — a layered lie. A detector does not need to know your real zone to score this: the contradiction is self-contained and provable from inside the page. N/A when no zone resolves.

How to resolve it

Spoof the timezone at the engine level so Intl and Date derive from one source (geoip/timezone in clearcote). Do not patch `Date.prototype.getTimezoneOffset` or `Intl` in userland JS — patching one leaves the other reporting the host's real offset.

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

Read in the wild by

PerimeterX / HUMAN

Its main.min.js collector reads the offset via a wrapper that returns the sentinel 9999 if the read throws, and ships that number in the same payload object as the Intl-resolved IANA zone and the rendered Date() string.

main.min.js `CD(){try{return(new Date).getTimezoneOffset()}catch(t){return 9999}}`, assigned at L8037 by `t[0]["OARNTn5iRnw="]=CD()`; same file sets the Intl zone at L5217 (`t[hQ(359)]=n.resolvedOptions()[hQ(360)]`, catch-fallback `t["UT0kdxRdI0Y="]="undef"`) and the Date string at L7898 (`t["Czt+cU1WeEM="]=hS[hQ(802)]()`). All three keys travel in one EV2 object: "OARNTn5iRnw=" = -480, "UT0kdxRdI0Y=" = "Asia/Shanghai", "Czt+cU1WeEM=" = "Tue May 19 2026 03:15:54 GMT+0800 (中国标准时间)"

CreepJS

CreepJS, an open-source research and education demo rather than a production detector, cross-checks the offset the host derives through Date against the offset implied by its Intl-resolved zone for the same instant (evaluated at a historical year, 1113), and when the two disagree it stops trusting the reported zone and re-derives a candidate city set from the Date offset instead — what it calls the zone failing to decrypt to itself.

src/timezone/index.ts L518-530: `const system = getTimezoneOffsetHistory({ year })` and `const resolvedOptions = getTimezoneOffsetHistory({ year, city: timeZone })`, compared at L525 `system == resolvedOptions ? [timeZone] : binarySearch(cities, filter)`, resolved at L530 `decryption.length == 1 && decryption[0] == timeZone ? timeZone : hashMini(decryption)`; year fixed at 1113 (L552); the no-city branch derives the host offset from Date alone (L500-505, `+new Date('7/1/1113')` vs `+new Date('1113-07-01')`), the city branch via `new Intl.DateTimeFormat('en', {timeZone: city})` (L499). Secondary (a Date-vs-Date cross-check, not Date-vs-Intl): `offset: new Date().getTimezoneOffset()` and `offsetComputed: getTimezoneOffset()` (L563-564), surfaced side by side at L604. Lie gate L546-550: `lieProps['Date.getTimezoneOffset'] || lieProps['Intl.DateTimeFormat.resolvedOptions']`, which marks the panel `rejected` at L597.

Kasada

Reads the zone as a string and the offset as a number, in both realms.

window_timezone_offset / iframe_timezone_offset, window_timezone_string / iframe_timezone_string

ips.js 427-probe teardown (emro.cat, Apr 2026)

Akamai

Lists Date.getTimezoneOffset() under browser-fingerprint signals.

signal_categories.md - 1. Browser Fingerprint - Timezone offset

Edioff/akamai-analysis — signal_categories.md

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

Nearby checks in Environment & locale

See all 23 checks in Environment & locale
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 Environment & locale 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 Environment & locale — the family timezone-offset-coherence belongs to.