Skip to content

What is screen fingerprinting?

Screen fingerprinting reads the display geometry a browser exposes: screen.width/height, availWidth/availHeight, colorDepth/pixelDepth, window.devicePixelRatio, and screen.orientation.type. On its own a resolution carries modest entropy — millions of devices report 1920×1080. Its value to a detector is that these numbers describe a physical thing, and several independent parts of the browser describe that same thing without consulting each other. See browser fingerprinting for the wider signal set.

The central mechanism is a two-source read of one quantity. screen.* is an ordinary JS property — one Object.defineProperty away from reporting anything. But the CSS media-query engine resolves device-width, device-height and resolution (in dppx) from the render surface the compositor was handed. Clearcote's free fingerprint audit tests exactly this: the screen-matchmedia check asks matchMedia("(device-width: Npx) and (device-height: Npx)") using the values screen just reported, and dpr-matchmedia asks for a resolution band around devicePixelRatio. Both answers are supposed to trace back to the same display metrics, so a disagreement says the JS surface was rewritten while rasterization continued at the true scale. Both are scored critical.

The DPR check has a subtlety worth copying: it feature-detects the resolution media feature first (reporting N/A where unsupported) and compares against a ±0.01 dppx tolerance band, not an exact value. Fractional ratios are genuinely real — Windows display scaling and Android densities produce values like 1.25 or 2.625 — and an exact matchMedia equality would fail honest browsers on a floating-point round-trip. A check that fires on real hardware teaches a detector nothing; the band keeps the assertion about contradiction rather than arithmetic.

The surrounding geometry checks are calibrated the same way. screen-plausible is only a sanity range (200–16384 px per axis) at warn: a 0×0 screen means nothing is being presented to a display, which is a headless tell rather than a contradiction. taskbar-present reports whether an OS chrome inset exists (avail smaller than screen on some axis, from a taskbar or dock) but stays info and is excluded from the score — fullscreen sessions and auto-hiding taskbars legitimately produce screen === avail. window-bounds asserts only the zoom-invariant rule: outerWidth/outerHeight must be non-zero, with the width fitting inside availWidth and the height inside screen.height (±1px). It deliberately does not assert inner ≤ outer, because zooming a page out legitimately grows innerWidth past outerWidth in a stock Chrome. A window larger than its own display is the classic residue of shrinking screen to a persona's resolution while the real window kept its size.

Two further checks read orientation and mechanism. orientation-vs-screen-dims (critical) requires portrait and height > width to agree in both directions — staying in device space, since the CSS (orientation:) media query is viewport-space and a half-screen snapped window really does resolve portrait on a landscape display; square and zero-sized screens are excluded rather than guessed at. And screen-descriptors (critical) ignores values entirely, asking whether width, height, avail*, colorDepth and pixelDepth still resolve through native Screen.prototype getters, with no own descriptors on the instance and no stray innerWidth/outerWidth names that belong to Window. That last one is the point: Object.defineProperty(screen, 'width', …) passes every value-plausibility test and still leaves the mechanism in plain view. The coherent options are to leave the screen real, or to give the browser a render surface of the size it claims — see coherence over camouflage.

Related reading

Q&AWhat is browser fingerprinting?Browser fingerprinting identifies a device by combining signals like canvas, WebGL, fonts, and hardware into a stable, often unique hash — without cookies.Q&AWhat is DOMRect fingerprinting?DOMRect fingerprinting hashes the sub-pixel geometry a browser reports for laid-out elements — values that depend on fonts, rasterizer and layout engine.Q&AWhat is WebGL fingerprinting?WebGL fingerprinting reads the GPU's render output plus driver strings (UNMASKED_VENDOR/RENDERER) and parameter limits — highly device-specific, and hard to fake coherently.Free toolWhat is my screen resolution?Your screen resolution as websites see it, the physical pixels and display scaling behind it, and your window and viewport size, live as you resize.ResearchCoherence over camouflage: why a plausible identity beats a hidden oneMost stealth tooling tries to hide. The signals that survive scrutiny don't hide — they agree with each other.Q&AHow is mobile emulation detected?A mobile claim spans maxTouchPoints, pointer/hover media, TouchEvent construction, orientation and UA-CH — emulation typically moves some but not all.Q&AHow is a headless browser detected?Detectors probe for headless tells: automation launch flags, missing or inconsistent browser APIs, software-render shortcuts, and behavior that differs from a windowed browser.DocsFingerprint flags and profilesReference for every Clearcote fingerprint switch: seed-derived personas, real Chrome profile imports, WebGPU/WebGL controls, locale, storage and canvas noise.

Clearcote puts this into practice

An open-source Chromium with fingerprint control compiled into the engine. A drop-in for Playwright & Puppeteer.

Free for one browser with GitHub. No card.