Android Chrome Mobile UA lacking navigator.contacts (a mobile-only web API)
br.android_no_contacts_api · convicts
What it catches
MOBILE-ONLY web-platform-API presence — a distinct axis from the GPU-substrate and device-manifold rungs. navigator.contacts (the ContactsManager / Contact Picker API) is present on Android Chrome 80+ (and ChromeOS) but is UNDEFINED on desktop Chrome: the documented support test is ('contacts' in navigator && 'ContactsManager' in window), false on every desktop platform (developer.chrome.com Contact Picker docs; MDN). Crucially, Playwright/CDP device emulation does NOT add it — it is a platform capability, not toggled by isMobile — so the FULL emulated Android node lacks it too (GROUNDED: KS_DEVICE=Pixel 5 reports 'contacts' in navigator = false, identical to a desktop). So a non-WebView Android Chrome Mobile UA WITHOUT navigator.contacts is a desktop wearing a phone UA — like br.mobile_cores_high, this catches the FULL Playwright emulation, not just a UA-only spoof. CONVICTING (w0.6). FP-SAFE: real Android Chrome (the UA claims a modern Chrome >= 80) exposes navigator.contacts; scoped to /Android/ + /Chrome/ + /Mobile/ and EXCLUDING Android WebView (UA token 'wv', which legitimately lacks the API). EXPERIMENTAL (calibration: assumes the UA-claimed modern Chrome; a pre-80 Android Chrome would be a rare confound). The RED counter is defining a fake navigator.contacts object (a shallow presence-spoof); the actual contacts.select() requires a real native picker + user gesture, the unspoofable follow-up. GROUNDED LIVE: KS_DEVICE='Pixel 5' (a full emulated Android Chrome node) FIRES android_no_contacts_api; a desktop Chrome UA is out of scope (not Android) and does not fire.
Signals it reads
browser.android_no_contacts_api
How it fires
present
Bypassed by 10
Frontier evaders that reach the detector uncaught (scored only suspicious, defeating every convicting tell) — this check is not one that stops them. The red-team frontier this detection still has to convict.