Why Chrome Still Carries AppleWebKit/537.36 — A Legacy of the UA String
Log navigator.userAgent in Chrome's dev tools console and you get this: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36. Strange, isn't it? Chrome is neither Netscape nor Apple, so why does the string carry "Mozilla" and "AppleWebKit" front and back? This isn't a bug — it's more than 20 years of accumulated web compatibility conventions that have simply calcified in place.
1. Mozilla/5.0: An Old Impersonation of Netscape
During the browser wars of the 1990s, websites often checked only whether "Mozilla" appeared in the UA string to decide "this is a proper modern browser" and serve it advanced features like frames and JavaScript. To keep Internet Explorer from being penalized on those sites, Microsoft started putting "Mozilla/4.0 (compatible; MSIE ...)" into IE's own UA string. Nearly every browser that came after — Safari, Chrome, even Firefox — has kept "Mozilla/5.0" at the front of its UA string for the same reason. Netscape itself disappeared long ago, but the signal "compatible with Mozilla" survived as a convention.
2. AppleWebKit/537.36: Why the Version Number Never Moves
Safari runs on the WebKit engine, and Chrome was WebKit-based early on too, before it split off into Blink (Blink is a fork of WebKit). The trouble is that countless websites wrote code that reasons: "if AppleWebKit shows up in the UA, this browser is WebKit-family, so it's compatible." If Chrome had kept updating the actual rendering engine version in its UA string, all that legacy compatibility code that checks only for "AppleWebKit/537.36" would risk failing to recognize Chrome and breaking. So Chrome (along with most other Blink/WebKit-based browsers) has long kept this token frozen at 537.36, never bumping it further. The actual, current engine version lives in a separate token further along in the UA string, like Chrome/128.0.0.0.
3. Dissecting a Real UA String
| Token | Actual meaning | Why it's still there |
|---|---|---|
| Mozilla/5.0 | Essentially meaningless (not Netscape) | Leftover from the 1990s "Mozilla = advanced browser" detection convention |
| AppleWebKit/537.36 | Signals WebKit-family lineage (not the actual latest version) | Value frozen to preserve compatibility with sites that check for 537.36 |
| (KHTML, like Gecko) | Marks WebKit's lineage from KDE's KHTML | Included to pass compatibility checks aimed at Gecko (Firefox) |
| Chrome/128.0.0.0 | The actual Chromium engine version | This is the only part actually updated with every release |
| Safari/537.36 | Signals Safari compatibility (not actually Safari) | Convention kept for sites that check for Safari |
4. How a UA Parser Filters Out These Legacy Tokens
The actual browser-detection logic in the User-Agent Parser tackles this problem head-on. In the code, when it detects the engine, it first sets engine = 'WebKit ' + version if it finds the pattern AppleWebKit/([0-9.]+), then separately checks whether a Chrome/ token also appears in the UA — and if it does, overwrites engine with 'Blink'. In other words, the mere presence of "AppleWebKit" alone can't tell you the real engine; you need to also check which other brand token comes along with it to correctly distinguish WebKit from Blink. Browser-name detection works the same way: a priority-ordered array of patterns is checked in sequence — Edg/ → OPR/ → SamsungBrowser/ → … → Chrome/ — and whichever matches first wins. Since Edge and Opera are also Chromium-based and carry "Chrome/" in their UA too, the more specific tokens have to be checked first to avoid misidentifying them.
5. Why You Shouldn't Trust the UA String
This patchwork of historical baggage alone makes the UA string a poor basis for definitively identifying a client. On top of that, a UA value can be freely altered (spoofed) via dev tools or a browser extension. And since Chrome 107+, the Privacy Sandbox policy (User-Agent Reduction) has frozen out details like minor version numbers and OS sub-versions from the UA string entirely, shifting the platform toward the User-Agent Client Hints API (navigator.userAgentData), where you request only the specific details you need. UA parsing is still useful for things like analytics or UI branching, but this entire structure is exactly why it shouldn't be used for security or access-control decisions.
Frequently Asked Questions
Q. Firefox is actually made by Mozilla — is it the one exception where "Mozilla" in the UA is genuine?
A. Firefox is indeed built by the Mozilla Foundation, but the UA string format itself ("Mozilla/5.0 (...) Gecko/... Firefox/...") follows the same compatibility convention as every other browser — it's not there because Firefox is "genuinely Netscape-lineage." The version number 5.0 is also a fixed value unrelated to the actual Firefox version.
Q. Is the AppleWebKit version really frozen at 537.36?
A. Yes. Chrome, Edge, Opera, and most other Blink/modern-WebKit-based browsers have shipped this value fixed at 537.36 for a long time now. Actual rendering-engine changes aren't reflected in that number at all — you can only see them in a separate token, like Chrome/xxx.
Q. How do bot UAs look different?
A. Search-engine crawlers like Googlebot and Bingbot generally don't hide themselves — they identify themselves explicitly in the UA with keywords like bot, crawler, or spider (e.g., Googlebot/2.1). Some malicious bots, however, imitate an ordinary browser UA outright to evade detection.
Q. Does User-Agent Client Hints fully solve this problem?
A. Only partially. Client Hints explicitly requests just the information you need, so it's more reliable than guessing by parsing the UA string — but it hasn't fully replaced UA parsing across every browser and server environment yet, so for now the two approaches coexist during this transition period.