Guide
How to read a User-Agent string
Read a User-Agent string from a log line, work out which tokens are frozen on purpose, and use Client Hints or feature detection for what the string can no longer tell you.
To read a User-Agent string, skip the first word, read the tokens from the right, and ask of every value whether it can still be true. The browser name and its major version usually can. The operating system version, the device model, and anything about Windows 11, a current Mac or iOS 26 usually cannot. Paste a string into the box above to follow along.
Start from the log line
This is a line from an nginx access log in the default combined format. The address is from a range reserved for documentation.
203.0.113.7 - - [24/Oct/2026:09:14:02 +0000] "GET /pricing HTTP/2.0" 200 5120 "https://example.com/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1"
The User-Agent is the last quoted field. To count the most common ones in a file, split on the double quote and take the sixth field:
awk -F'"' '{print $6}' access.log | sort | uniq -c | sort -rn | head
On a four-line sample file this printed the iPhone string first, with a count of 2.
Read it in five steps
- Ignore the first word.
Mozilla/5.0is not a version. MDN says almost every browser still sends it for historical reasons. - Read the tokens from the right. The most specific name sits near the end. A string that ends
Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0is Microsoft Edge, because Edge addsEdgafter the Chrome tokens. Opera addsOPR. Safari putsVersion/beforeSafari/, which Chromium browsers do not. - Open the parentheses. They hold the platform:
Windows NT 10.0; Win64; x64,Macintosh; Intel Mac OS X 10_15_7,X11; Linux x86_64,Linux; Android 10; K,iPhone; CPU iPhone OS 18_6 like Mac OS X. - Look for Mobile. MDN's rule of thumb is to look for
Mobianywhere in the string. A phone on Chrome hasMobilebeforeSafari/. A tablet does not. - Check every value against the frozen list below.
Walk through the iPhone line
Mozilla/5.0is the skipped word.(iPhone; CPU iPhone OS 18_6 like Mac OS X)is an iPhone. It claims iOS 18.6. The wordslike Mac OS Xare a legacy claim.AppleWebKit/605.1.15names the WebKit engine.Version/26.0is Safari 26.0.Mobile/15E148confirms a phone. Ignore the build code.Safari/604.1is a trailing compatibility token.
So this is Safari 26 on an iPhone. The OS number needs care. The parser above prints iOS 26.0 for it, and it gets there by copying the Safari version into the OS field, because Safari 26 no longer sends the real iOS version. The next section says why.
Which values are frozen on purpose
- Chrome and Edge on desktop send
Windows NT 10.0for Windows 10 and for Windows 11,Intel Mac OS X 10_15_7on a Mac andX11; Linux x86_64on Linux. The version ends in.0.0.0. Chrome froze the minor version from Chrome 101 and reduced desktop platform tokens from Chrome 107. - Chrome and Edge on Android send
Android 10; K, the same for every phone. Chrome reduced these from Chrome 110.Kis a placeholder where the model used to be. - Safari on a Mac says
10_15_7whatever the macOS release. An iPad in its default mode sends the same Macintosh string, so it looks like a Mac. - Safari 26 on iOS says
18_6. The WebKit release notes of 15 September 2025 say the string no longer lists the current OS version, and a WebKit developer called the freeze permanent. Chrome on iOS still reports the real version. - Firefox fixes
Gecko/20100101on desktop. From Firefox 110 it heldrv:at 109 because some sites readrv:11as Internet Explorer.
The practical rule: browser family, engine family and major browser version are usable. The OS version is not. The device model is not. If your analytics shows an OS version column built from the User-Agent, every Windows 11 visitor is in the Windows 10 row.
Use Client Hints for the rest
Chromium browsers send three hints with every HTTPS request: Sec-CH-UA (brand and major version), Sec-CH-UA-Mobile and Sec-CH-UA-Platform. Anything finer is only sent after the server asks for it with an Accept-CH response header. The exchange looks like this, using the sample values from Microsoft's documentation:
GET /download HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Edg/120.0.0.0
Sec-CH-UA: "Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"
HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Platform-Version
GET /download HTTP/1.1
Sec-CH-UA-Platform-Version: "15.0.0"
Three things to know before you rely on this.
First, the values arrive inside double quotes, so strip them before you compare.
Second, a first number of 13 or higher in Sec-CH-UA-Platform-Version means Windows 11. Microsoft's Windows 11 page and sample code use 13. Its general Edge page says 14.0.0 or later. Use 13, and see the User Agent Parser page for the note.
Third, support is narrow. MDN's compatibility data lists Chrome, Edge and Opera, and shows no support in Firefox or Safari. navigator.userAgentData, the JavaScript side, is also missing from Android WebView in that data. For those clients the User-Agent is all you get.
Bots and crawlers
A crawler usually keeps the Mozilla prefix and adds its name and an info URL in a comment. Google's desktop string contains compatible; Googlebot/2.1; +http://www.google.com/bot.html, followed by a Chrome version Google writes as W.X.Y.Z. OpenAI publishes three tokens with three jobs: GPTBot collects content that may be used for training, OAI-SearchBot feeds ChatGPT search, and ChatGPT-User acts when a person asks. OpenAI says robots.txt rules may not apply to ChatGPT-User. Anthropic's help article names ClaudeBot, Claude-User and Claude-SearchBot but does not print the full header, so match the name and not the whole line.
Not every bot starts with Mozilla. curl/7.64.1 does not. A User-Agent echo page showed one assistant-driven fetch as Claude-User (claude-code/2.1.308; +https://support.anthropic.com/), with no Mozilla prefix at all. In the parser above, curl and that string both come back empty. OpenAI's two published strings and the ClaudeBot string reported by third parties come back with the engine, WebKit 537.36, as the browser, because the tool does not run bot detection.
Treat the string as a claim. A Windows Chrome string with Googlebot/2.1 appended parses as a normal Chrome visit. To confirm a Googlebot visit, Google says to run a reverse DNS lookup on the IP address, check the domain is googlebot.com, google.com or googleusercontent.com, then resolve that name forward and confirm it returns the same address. Google also publishes IP range files for large-scale checks.
When not to use the User-Agent
- To decide whether a feature exists. MDN calls this the worst reason to sniff. Test the feature itself, or use
@supportsin CSS. - To pick a layout. Use media queries. MDN suggests
navigator.maxTouchPointsover a mobile regular expression when you need to know about touch. - To make a security decision. The string is whatever the client sends. RFC 9110 itself notes that a client that masquerades as another is treated as asking for responses tailored to that product.
- To report OS versions. The OS part is frozen on the main browsers, as above.
- As a cache key. Varying a cached response on
User-Agentcreates one copy per distinct string, and there are very many distinct strings.
It is a good fit for reading logs, triaging a bug report ("it only breaks on this browser"), and counting browser families. RFC 9110 lists those uses: working out the scope of interoperability problems, and analytics on browser use.
Sources
Checked on 24 October 2026:
- Chromium: User-Agent reduction plan and formats
- Microsoft Edge: Detect Windows 11 using User-Agent Client Hints and Detecting Microsoft Edge from your website
- WebKit blog: WebKit features in Safari 26.0 and WebKit bug 298473
- MDN: User-Agent header, Browser detection using the user agent, Client hints and NavigatorUAData compatibility data
- RFC 9110, section 10.1.5 (June 2022)
- Mike Taylor: Firefox freezes rv at 109 (29 December 2022)
- Google: common crawlers and verifying Googlebot
- OpenAI: crawlers and user agents
- Anthropic: crawler help article