Quick answer: A user-agent (UA) string is the line of text your browser or script sends with every HTTP request to identify itself: the browser, its version, the operating system, and the rendering engine. To look one up, paste it into any UA parser (the interactive breakdown below shows exactly which token maps to what), or read it left to right. The value your own browser is sending is available in JavaScript as navigator.userAgent, and every request you make already includes it in the User-Agent header.
If a site is treating you differently than you expect, blocking a script, serving a mobile layout, or throwing a 403, the UA string is usually the first thing worth inspecting.
How to Read a User-Agent String
Modern UA strings look like a pileup of historical baggage, and that is exactly what they are. Here is a common desktop Chrome string, decoded token by token:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
| Token | What it means |
|---|---|
Mozilla/5.0 |
Legacy prefix. Almost every browser claims to be Mozilla for backward compatibility. It tells you nothing useful. |
Windows NT 10.0 |
The operating system. NT 10.0 covers Windows 10 and 11. |
Win64; x64 |
64-bit platform architecture. |
AppleWebKit/537.36 |
The rendering engine lineage. Chrome inherited WebKit, then forked it into Blink, but kept the token. |
(KHTML, like Gecko) |
More compatibility theater, dating back to Konqueror and Firefox. |
Chrome/126.0.0.0 |
The real browser and major version. This is the token most servers actually read. |
Safari/537.36 |
Present because Chrome once wanted to be recognized by Safari-targeting code. |
The practical lesson: most of a UA string is vestigial. The parts that matter for detection are the OS block in parentheses and the real browser token (Chrome/126, Firefox/128, Edg/126, and so on).
Mobile strings add device hints. An iPhone reports (iPhone; CPU iPhone OS 17_5 like Mac OS X), and Android reports the device model, for example (Linux; Android 14; Pixel 8). Bots are often the most honest of all: Googlebot sends Googlebot/2.1 (+http://www.google.com/bot.html), and plain scripts frequently announce themselves with something like python-requests/2.31.0 or curl/8.4.0.
Look Up Your Own User-Agent in Two Seconds
You do not need a website to see what you are sending. Open your browser console (F12, then the Console tab) and run:
console.log(navigator.userAgent)
From a terminal, any of these prints the UA a command-line tool sends by default:
curl -A "" https://httpbin.org/user-agent # send an empty UA
curl https://httpbin.org/user-agent # see curl's default UA
The httpbin.org/user-agent endpoint simply echoes back the header it received, which makes it a handy loopback for confirming what any client actually transmits after your overrides.
Why the User-Agent String Matters
Servers read the UA header on the very first request, before any JavaScript runs, and they make decisions with it:
- Content negotiation. Sites serve a mobile layout to mobile UAs and a desktop layout otherwise. Wrong UA, wrong page.
- Feature gating. Some sites still branch on browser version to enable or disable features.
- Bot filtering. This is the big one for anyone writing scripts. A UA like
python-requests/2.31.0is an instant tell that you are automated, and many sites block it outright or route it to a challenge. - Analytics. Traffic dashboards bucket visitors by parsed UA, which is why a mislabeled UA can quietly skew someone's numbers.
That third point is where a lookup tool stops being trivia and starts being operational. If you are getting blocked, comparing the UA your script sends against the UA a real browser sends is the fastest diagnosis available.
User-Agents and Web Scraping
When you fetch a page with a default library UA, you are broadcasting "I am a bot" on every request. The first fix most people reach for is setting a realistic browser UA:
import requests
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/126.0.0.0 Safari/537.36"
)
}
resp = requests.get("https://example.com", headers=headers)
This helps, but it is not a silver bullet, and understanding why saves a lot of wasted effort.
Rotating user-agents has limits. Cycling through a list of UA strings spreads your fingerprint so a single header does not stand out. It defeats the crudest filters. But a rotated UA still travels over the same IP, in the same TLS handshake, with the same header ordering as your script's default, and modern anti-bot systems fingerprint all of those. A rotated UA on top of a python-requests TLS signature is a mismatch that sophisticated defenses catch immediately. For the full picture of where header spoofing ends and real browser emulation begins, see curl vs headless vs stealth browser.
Consistency beats variety. A UA claiming Chrome 126 on Windows should be paired with the header set, Accept, Accept-Language, Sec-Ch-Ua client hints, that a real Chrome 126 on Windows actually sends. A convincing-looking UA surrounded by inconsistent headers is often more suspicious than an honest one. This coherence problem is a recurring theme in scraping Cloudflare-protected sites and behind blocks like Cloudflare error 1020.
A wrong UA can also cause rate-limit trouble. If your UA gets you flagged as a bot, sites tighten limits fast, and you start collecting 429 Too Many Requests errors that a cleaner request profile would have avoided.
Common User-Agent Strings for Reference
| Client | Example UA token |
|---|---|
| Chrome (Windows) | Chrome/126.0.0.0 ... Windows NT 10.0 |
| Safari (macOS) | Version/17.5 Safari/605.1.15 |
| Firefox (Linux) | Firefox/128.0 ... X11; Linux x86_64 |
| iPhone Safari | Mobile/15E148 ... iPhone OS 17_5 |
| Googlebot | Googlebot/2.1 (+http://www.google.com/bot.html) |
| Python requests | python-requests/2.31.0 |
| curl | curl/8.4.0 |
Keep in mind that any UA can be forged. A request claiming to be Googlebot might be a scraper in disguise, which is why serious operators verify Googlebot by reverse DNS rather than trusting the header. The UA string tells you what a client wants you to believe, not what it is.
When You Would Rather Not Manage Headers at All
Parsing UA strings is useful for debugging and analytics. Manually assembling a coherent, consistent header profile for every target site, then keeping it aligned with your IP and TLS fingerprint, is a maintenance treadmill.
A managed fetch layer like link.sc sends realistic, internally consistent browser signatures on your behalf, so you send one API call per URL and stop hand-tuning User-Agent headers, client hints, and IP rotation. The page comes back as clean content (or Markdown, if you are feeding an LLM), and the header-coherence problem stops being your code's concern.
The Bottom Line
A user-agent string is a self-report: browser, version, OS, and engine, wrapped in decades of compatibility cruft. Reading it is easy once you know that the OS parentheses and the real browser token are the only parts that carry weight. For scraping, a realistic UA is table stakes but not sufficient on its own, because detection now spans IP, TLS, and full header coherence. Look yours up, understand what it broadcasts, and treat the UA header as one signal among several rather than a magic key.
Stop hand-tuning user-agent headers for every site. Try link.sc free: realistic browser signatures and clean web data from a single API call.