How is mobile emulation detected?
A mobile identity is not a single value. A detector asking whether a browser really is a phone reads a cluster of independent surfaces: navigator.maxTouchPoints, the (any-pointer:) and (hover:) media features, whether 'ontouchstart' in window and document.createEvent('TouchEvent') work, screen.orientation.type against screen.width/screen.height, and the UA-CH mobile flag and platform. On real hardware all of these are populated from the same platform description, so they cannot disagree by accident. A desktop browser with device emulation toggled on typically moves some of them and not others — and the gap between the moved and the unmoved signals is the tell, not any individual value.
The touch stack is the first cluster, and it is tested one-directionally on purpose. Clearcote's open browser audit scores touch-pointer-coherence: if maxTouchPoints > 0, then matchMedia("(any-pointer: coarse)") is expected to match — a touch count written onto navigator with no digitiser behind it fails, while maxTouchPoints = 0 imposes no requirement. Alongside it, touch-createevent-coherence requires that a UA matching iPhone|iPad|iPod|Android reports maxTouchPoints > 0 and can construct a TouchEvent via document.createEvent. The createEvent leg is the load-bearing one: it is gated by the engine's internal event-factory table rather than a navigator binding, so no Object.defineProperty reaches it.
Neither check asserts the converse — touch present, therefore the UA must be mobile — because real iPadOS desktop-mode Safari and every touchscreen laptop would hard-fail it. The desktop direction is scored separately by pointer-hover-desktop, which applies only when the UA names a desktop platform (Windows, Macintosh, Mac OS X, X11, Linux, CrOS, and not Android/Mobile) and maxTouchPoints is 0. It then requires both (any-pointer: fine) and (hover: hover) to match; an environment with no pointing device attached matches neither, which is why this doubles as a headless-detection signal.
Geometry is where a half-applied mobile persona shows most clearly, and here the assertion runs in both directions. orientation-vs-screen-dims (severity critical) reads screen.orientation.type and requires a type starting with portrait exactly when screen.height > screen.width — so a landscape type over a taller-than-wide screen fails just as a portrait type over a landscape one does. It stays deliberately in device space and does not consult the CSS (orientation:) media query, which is viewport-space — a half-screen snapped desktop window genuinely resolves portrait while the screen is landscape. Square and zero-dimension screens are excluded from scoring rather than guessed at. What remains is a clean inference: a portrait orientation over landscape host dimensions is a mobile orientation value layered onto a desktop display. See screen fingerprinting for the rest of that surface.
The identity fields have to line up too. platform-coherence (also critical) normalises three surfaces — the UA string, navigator.platform, and navigator.userAgentData.platform — to one OS family and requires all three to match; when UA-CH is absent it is treated as agreeing rather than penalised. uach-highentropy then awaits getHighEntropyValues() and compares fullVersionList's Chrome major and the hinted platform against what the UA implies. An Android UA beside a Win32 platform, or a mobile UA whose high-entropy platform still reports Windows, identifies a field that was edited by hand. See User-Agent Client Hints.
The through-line is that none of these are checks on mobile-ness — they are checks on agreement, which is why they behave the same for any persona. A property override also has to survive re-reading: the audit's iframe probe compares maxTouchPoints (and the screen fields, and devicePixelRatio) between a fresh realm and the main one, so a spoof scoped to the top window diverges immediately. Resolving the contradiction means making the environment genuinely be what it claims — touch registered at the engine level, one coherent display description, one persona driving UA, platform and hints — rather than patching properties individually. See coherence over camouflage and how detection works.