Why user agent strings look like contradictions
A modern Chrome user agent looks like: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36. It claims to be Mozilla, Apple WebKit, and Safari — even though it's Chrome. This is historical: early browsers added "Mozilla/5.0" because web servers used that prefix to identify capable browsers. Every subsequent browser copied it to avoid being served degraded content. The pattern compounded over decades. Firefox says "Gecko". Chrome says "AppleWebKit" and "Safari". Edge says "Chrome" and "Safari".
What you can and can't reliably detect
- Reasonably reliableMobile vs. desktop (look for "Mobile" token), OS family (Windows / Mac / Linux / Android / iOS), rendering engine (Gecko vs. WebKit vs. Blink). These change slowly and are present in most real browsers.
- UnreliableExact browser version (easily spoofed), bot detection (good bots identify themselves; bad bots fake Chrome), exact device model on Android (fragmented across manufacturers).
- Better alternativeFor feature detection, use
navigator.userAgentData(User-Agent Client Hints, available in Chrome/Edge). For feature support, useCSS.supports()orif ('fetch' in window)— test the capability, not the browser identity.
