A UA claiming Safari lacks window.GestureEvent — a WebKit-only surface, so it is not WebKit
br.safari_ua_no_webkit_api · convicts
What it catches
The negative-surface complement to apple_ua_nonwebkit (which keys on Blink APIs PRESENT under a Safari UA). window.GestureEvent is a WebKit-ONLY global — the multi-touch gesture API present in every desktop and iOS Safari (since Safari 5), and in every iOS browser (all WebKit by Apple mandate). Blink (Chromium) and Gecko (Firefox) have NO window.GestureEvent. GROUNDED on the real-browser second source: a live Playwright WebKit reports typeof window.GestureEvent === 'function' while a live Chromium AND Firefox report 'undefined'. So a UA claiming Safari (uaEngine 'safari') WITHOUT window.GestureEvent is a non-WebKit engine faking Safari — the collector fires safari_ua_no_webkit_api only in that case. Complementary to apple_ua_nonwebkit and harder to evade: a spoof that DELETES window.chrome / navigator.userAgentData to beat that positive-API rule still cannot synthesise a real WebKit GestureEvent surface. FP-safe: every real Safari/iOS browser exposes GestureEvent → never fires on a real Safari; a real Chrome/Firefox has uaEngine chromium/firefox so the rule is gated off (unknown never fires). Live positive: the ios-ua-spoof evader (Playwright Chromium under an iPhone Safari UA) trips it. Browserforge calibration does not emit GestureEvent, so it cannot raise the legit flag rate.
Signals it reads
browser.safari_ua_no_webkit_api
How it fires
present
Evaders it caught 2
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.