Skip to content
All fingerprint checksScreen & display

screen dimensions resolve via native prototype getters

Check id screen-descriptors

What an ordinary browser yields

width/height/avail*/colorDepth/pixelDepth are all native Screen.prototype getters, with no own descriptors on screen and no window-geometry properties present.

What a detector infers

For width, height, availWidth, availHeight, colorDepth and pixelDepth this asks two questions: does the screen instance carry an own descriptor (real browsers expose these only via Screen.prototype), and is the Screen.prototype entry still a native getter rather than a data property or a JS function. It also checks four tripwire names — innerWidth, innerHeight, outerWidth, outerHeight — which belong to Window and never to Screen; their presence on screen indicates a catch-all Proxy or a spoof mirroring window geometry onto the screen object. The reason this is severity 'critical' is that Object.defineProperty(screen,'width',{get:…}) is the most common patch there is, and it never changes a value's plausibility, so every value-coherence check still passes while the mechanism is plainly visible in the descriptor. One calibration note: the getter's native-code formatting is held to byte-exact equality on V8 only — descriptor placement and the tripwires are engine-neutral, but native stringification formatting is not, and genuine Firefox and Safari failed the exact test 100% in the corpus. Off V8 the getter is held to the loose [native code] marker instead.

How to resolve it

Spoof the screen at the engine level rather than via Object.defineProperty on the screen instance, which leaves both an own descriptor and a JS getter behind. Note that this check inspects mechanism, not values: leaving the real screen values in place passes it outright, which is often the simplest option.

What is screen fingerprinting?

Read in the wild by

CreepJS

CreepJS, a research demo rather than a production detector, walks every Screen property and specifically flags an own descriptor sitting on the screen instance rather than on Screen.prototype — which is where a defineProperty spoof lands.

src/lies/index.ts: `['failed undefined properties']: (!!obj && /^(screen|navigator)$/i.test(objName) && !!(Object.getOwnPropertyDescriptor(self[objName.toLowerCase()], name) || (HAS_REFLECT && Reflect.getOwnPropertyDescriptor(self[objName.toLowerCase()], name))))` — objName 'Screen' resolves self['screen'] to the instance; plus `searchLies(() => Screen)` with no `target` ("remove target to search all properties", enumerating `[...new Set([...Object.getOwnPropertyNames(interfaceObject), ...Object.keys(interfaceObject)])].sort().forEach((name)`); and src/screen/index.ts reads `lieProps['Screen.width'] || lieProps['Screen.height'] || lieProps['Screen.availWidth'] || lieProps['Screen.availHeight'] || lieProps['Screen.colorDepth'] || lieProps['Screen.pixelDepth']`.

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

Nearby checks in Screen & display

See all 15 checks in Screen & display
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 Screen & display 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 Screen & display — the family screen-descriptors belongs to.