← Back to blog

The Developer's User-Agent List: 2026 Reference Guide

August 6, 2026
The Developer's User-Agent List: 2026 Reference Guide

TL;DR:

  • User-agent strings are client-controlled claims used primarily for analytics and compatibility, not security verification.
  • Modern browsers reduce UA detail, relying on Client Hints and TLS fingerprints for accurate identification.

Here are eight copy-pasteable user-agent strings covering the most common scenarios. Grab what you need, then read the section that matches your use case.

Desktop browsers:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0
Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15

Mobile and automation:

Mozilla/5.0 (Linux; Android <version>; <device model>) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<major>.<minor>.<build>.<patch> Mobile Safari/537.36
Mozilla/5.0 (iPhone; CPU iPhone OS <version> like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/<major>.<minor> Mobile/<build> Safari/<build>
curl/8.7.1
python-requests/2.31.0

One rule applies to every string above: a User-Agent header is a client-controlled claim, not a verified identity. Use it for analytics, compatibility routing, and debugging. Never treat it as the sole basis for a security decision.

Quick verification with curl:

curl -I -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" https://httpbin.org/headers

The server echoes back the headers it received. If the User-Agent field matches what you sent, your client is passing the string correctly. What the server does with it next is a separate question entirely.

Pro Tip: Use https://httpbin.org/headers or https://httpbin.org/user-agent as a zero-setup echo endpoint during development. It returns the exact headers your client transmitted, including the UA string, with no authentication required.


Table of Contents

Desktop browser user-agent strings, explained

Every major desktop browser follows the same basic structure: Mozilla/5.0 (<system-info>) <platform> (<platform-details>) <extensions>. The Mozilla/5.0 prefix is a historical artifact that every browser carries for compatibility reasons. What actually identifies the browser sits in the extension tokens at the end.

Woman working on desktop browser user-agent data

BrowserKey identifying tokensExample UA string
ChromeChrome/<major version>.0.0.0 Safari/537.36Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<major version>.0.0.0 Safari/537.36
EdgeEdg/<major version>.0.0.0 (note: single g)Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<major version>.0.0.0 Safari/537.36 Edg/<major version>.0.0.0
FirefoxGecko/20100101 Firefox/<major version>.0Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:<major version>.0) Gecko/20100101 Firefox/<major version>.0
Safari 17 (macOS)Version/17.4.1 Safari/605.1.15Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15
Brave (Chromium)Same as Chrome; no Brave token in UAMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36

Brave deliberately omits any Brave-specific token from its UA string. You cannot distinguish Brave from Chrome via UA alone. That is by design.

UA reduction is the bigger structural shift. Chrome and Chromium-based browsers now freeze the minor version at 0.0.0 and omit device model details from the UA string. The full version, platform architecture, and device model are only available through Sec-CH-UA-* Client Hints headers, which require an explicit Accept-CH negotiation from the server. If you are building a parser that relies on extracting minor build numbers from Chrome UA strings, it will return 0 for most modern traffic.

  • Sec-CH-UA: brand and major version (e.g., "Chromium";v="124", "Google Chrome";v="124")
  • Sec-CH-UA-Platform: OS name ("Windows", "macOS")
  • Sec-CH-UA-Mobile: boolean (?0 or ?1)
  • Sec-CH-UA-Full-Version-List: full version, sent only when the server requests it

Pro Tip: If your server-side code needs the full Chrome version or device model, request Client Hints via Accept-CH rather than parsing the frozen UA string. You get structured data instead of a regex that breaks on every major release.


Mobile and OS-specific user-agent strings

The clearest signal that a UA string comes from a mobile browser is the Mobile token, usually appearing as Mobile Safari/537.36 in Chromium-based browsers or Mobile/15E148 in iOS Safari. The Mobi substring (present in Mobile) is what MDN recommends checking for mobile detection, since it appears consistently across Android Chrome, Samsung Internet, and iOS Safari.

Hands holding smartphone analyzing user agents

Representative strings by platform:

# Android — Chrome on Pixel 8 (Android 14)
Mozilla/5.0 (Linux; Android <version>; <device model>) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<major>.<minor>.<build>.<patch> Mobile Safari/537.36

# iPhone — Safari on iOS 17
Mozilla/5.0 (iPhone; CPU iPhone OS <version> like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/<major>.<minor> Mobile/<build> Safari/<build>

# iPad — Safari on iPadOS 17 (no "Mobile" token)
Mozilla/5.0 (iPad; CPU OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/604.1

# Windows 11 — Chrome desktop
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36

# macOS Sonoma — Chrome desktop
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36

# Linux — Firefox desktop
Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0

Notice that the iPad string drops the Mobile token entirely. iPadOS Safari presents itself as a desktop-class browser by default. If you are routing tablet traffic differently from phone traffic, UA alone is unreliable for that distinction.

PlatformKey tokenNotes
AndroidLinux; Android <version>Device model present in older strings; frozen in reduced UAs
iPhoneiPhone; CPU iPhone OSiOS version uses underscores, not dots
iPadiPad; CPU OSNo Mobile token; treated as desktop by many servers
WindowsWindows NT 10.0; Win64; x64NT 10.0 covers both Windows 10 and 11
macOSMacintosh; Intel Mac OS XVersion uses underscores
LinuxX11; Linux x86_64Common in developer environments

Capturing the UA in JavaScript is straightforward:

// Legacy string — works everywhere
const uaString = navigator.userAgent;

// Structured Client Hints — Chromium only, requires secure context
if (navigator.userAgentData) {
  const hints = await navigator.userAgentData.getHighEntropyValues([
    "platform", "platformVersion", "model", "fullVersionList"
  ]);
  console.log(hints);
}

In-app browsers add another layer of complexity. Facebook, Instagram, LinkedIn, and TikTok all inject their own tokens into the UA string (e.g., FBAN/, Instagram, LinkedInApp). If your analytics show unexpected mobile traffic, check for these tokens before assuming it is standard mobile Safari or Chrome.

Pro Tip: Device model tokens in Android UA strings are increasingly absent or frozen. For reliable device-class detection (phone vs. tablet vs. desktop), use Sec-CH-UA-Mobile and Sec-CH-UA-Form-Factor Client Hints rather than parsing the model string from the UA.


How to identify and verify crawler and bot user-agents

Major search engine crawlers identify themselves with recognizable UA strings. Here are the most common ones:

# Googlebot (web crawler)
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)

# Googlebot Smartphone
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)

# Bingbot
Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)

# DuckDuckBot
DuckDuckBot/1.0; (+http://duckduckgo.com/duckduckbot.html)

# Generic archive/research crawler
Mozilla/5.0 (compatible; archive.org_bot +http://www.archive.org/details/archive.org_bot)

The critical point: any client can send any of these strings. A UA claiming Googlebot/2.1 is not Googlebot unless you verify it. The correct verification procedure uses forward-confirmed reverse DNS (FCrDNS):

  1. Take the source IP of the incoming request.
  2. Run a reverse DNS lookup: host <IP> or dig -x <IP>. The result should resolve to a hostname ending in googlebot.com or google.com.
  3. Run a forward lookup on that hostname: host <hostname>. It must resolve back to the original IP.
  4. Cross-reference against Google's published IP ranges (available via their Search Console documentation).

Only when steps 2, 3, and 4 all pass can you treat the request as legitimate Googlebot traffic.

Verification command sequence (Linux/macOS): host 66.249.66.1 → should return 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com Then: host crawl-66-249-66-1.googlebot.com → must resolve back to 66.249.66.1 If the forward and reverse don't match, the declared UA is spoofed regardless of what it says.

Pro Tip: Log both the declared UA string and the FCrDNS result for every request that claims to be a known crawler. That pairing gives you an auditable record if you ever need to dispute a crawl rate complaint or investigate unusual traffic spikes.


Headless browser and automation library user-agent strings

Automation tools ship with default UA strings that are immediately recognizable to any WAF worth its subscription fee. Here are the defaults:

# Puppeteer / Playwright (Chromium-managed)
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/124.0.0.0 Safari/537.36

# Selenium WebDriver (Chrome)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36

# curl (default)
curl/8.7.1

# python-requests (default)
python-requests/2.31.0

# Go net/http (default)
Go-http-client/2.0

The HeadlessChrome token in Puppeteer's default UA is a direct flag. Replacing it with a standard Chrome string is a one-line fix, but it only solves the UA layer. WAFs like Cloudflare and DataDome identify bot traffic via JA3/JA4 TLS fingerprinting and HTTP/2 frame analysis before they even read the UA string. A Python requests client with a Chrome UA still presents a Python OpenSSL TLS ClientHello. That mismatch is the actual detection signal.

ClientDefault UA flagTLS fingerprint issue
Puppeteer (default)HeadlessChrome tokenMatches real Chrome if using bundled Chromium
python-requestspython-requests/x.x.xPython OpenSSL stack; JA3 does not match any browser
curlcurl/x.x.xcurl TLS stack; JA3 is curl-specific
Go net/httpGo-http-client/x.xGo crypto/tls stack; distinct JA3
Selenium (Chrome)Standard Chrome UAMatches Chrome if using real Chrome binary

Randomizing UA tokens without matching the underlying network stack often makes detection easier, not harder. A unique combination of UA string, TLS fingerprint, and HTTP/2 frame ordering that matches no real-world browser distribution is a stronger signal than any single flag.

Pro Tip: For Puppeteer and Playwright, launch with a real Chrome binary rather than the bundled Chromium when TLS fingerprint fidelity matters. The bundled Chromium and a full Chrome install produce different JA3 hashes on some builds. Use executablePath in Puppeteer or channel: 'chrome' in Playwright to specify the system Chrome.


Tools and APIs for parsing and decoding user-agent strings

Parsing a UA string by hand with regex is how you end up with a 400-line switch statement that breaks on every Safari release. Use a library or a dedicated service instead.

Online decoders and searchable databases:

  • WhatIsMyBrowser (whatismybrowser.com): Paste any UA string and get a structured breakdown of browser, engine, OS, and device type. The site also maintains a searchable user-agent database with update timestamps, which makes it useful for validating whether a string you found in a log is current or years out of date.
  • DeviceAtlas: A commercial device intelligence platform that maps UA strings and Client Hints to a detailed device property set (screen size, hardware class, OS version). DeviceAtlas maintains one of the most comprehensive user-agent databases available and exposes an API for server-side lookups. It is the standard choice for teams that need reliable device classification at scale.
  • pzb/user-agents gist (GitHub): A community-maintained list of real-world UA strings scraped from browser traffic. Useful as a rotation source or for testing parsers against realistic inputs. Check the commit date before using it in production; the value of any static UA list degrades as browsers update.

Open-source parsing libraries:

  1. ua-parser-js (npm): Parses UA strings in JavaScript (browser and Node.js). Returns browser, engine, os, device, and cpu objects. Widely used and actively maintained.
  2. uap-python / uap-ruby / uap-java: Language bindings for the ua-parser project, which uses a shared regexes.yaml definition file. Updating the regex file keeps all bindings current without changing application code.
  3. browscap (PHP/Python): The Browser Capabilities Project maintains a large device database in CSV and INI formats. Slower than regex-based parsers but covers a wider device set.
  4. device-detector (PHP, Python port available): Parses UA strings into device type, brand, model, OS, and client application. Handles bots, feed readers, and mobile apps in addition to browsers.

A note on parser accuracy: No open-source parser is 100% current. UA reduction means that Chrome's minor version is always 0.0.0 in the UA string, so any parser that reports a specific minor version for Chrome is either reading Client Hints or fabricating precision. Treat parsed minor versions from UA strings as unreliable for Chromium-based browsers.

Pro Tip: Pin your parser's regex definition file to a specific commit in CI, then update it on a scheduled cadence (monthly works for most teams). An unpinned dependency that auto-updates can silently change how your analytics categorize traffic between deploys.


How to find your current user-agent string

Three methods, ordered by how much context they give you.

Method 1: Browser developer tools (most complete)

  1. Open Chrome, Edge, or Firefox and press F12 to open DevTools.
  2. Go to the Network tab.
  3. Navigate to any page or reload the current one.
  4. Click any request in the list.
  5. Open the Headers tab in the request detail panel.
  6. Find User-Agent under Request Headers.

This shows the exact string the browser sent, including any modifications made by extensions. It is the ground truth for what the server received.

Method 2: JavaScript console (fastest)

// Works in every browser
console.log(navigator.userAgent);

// Chromium only — structured and privacy-aware
if (navigator.userAgentData) {
  navigator.userAgentData.getHighEntropyValues([
    "architecture", "model", "platform", "platformVersion", "fullVersionList"
  ]).then(data => console.log(data));
}

navigator.userAgentData is only available in Chromium-based browsers (Chrome, Edge, Brave) in a secure context (HTTPS or localhost). Firefox and Safari do not implement it.

Method 3: Command line

# Print the default curl UA
curl -I https://httpbin.org/user-agent

# Send a custom UA and verify the server received it
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" https://httpbin.org/user-agent

# Python — print requests' default UA
python3 -c "import requests; print(requests.utils.default_headers()['User-Agent'])"
MethodWhat you getBest for
DevTools Network tabFull request headers as sentDebugging browser behavior
navigator.userAgentUA string onlyQuick JS checks
navigator.userAgentDataStructured brand/version/platformChromium; Client Hints integration
curl -IServer-confirmed echoCLI clients and automation
Python snippetLibrary default UAVerifying requests library version

A note on TLS fingerprints: if you need to correlate your client's JA3 hash with its UA string for server-side analysis, tools like ja3 (a Wireshark plugin) or tlsfuzzer can capture the ClientHello from a live connection. That pairing, UA plus JA3, is what server-side detection systems actually compare.


Best practices: feature detection over UA sniffing

Mozilla's guidance is direct: UA sniffing is brittle and should be a last resort. The practical rules are short:

  • Use feature detection first. Check whether fetch, IntersectionObserver, or CSS.supports('display', 'grid') exists before branching on browser name. Features are facts; UA strings are claims.
  • Use Client Hints for device data. If you need OS, platform, or device class on the server side, request Sec-CH-UA-* headers via Accept-CH. You get structured, negotiated data instead of a string you have to parse.
  • Treat UA as untrusted for security decisions. The UA header is trivial to forge; JA3/JA4 TLS fingerprinting, HTTP/2 frame ordering, and runtime JavaScript API checks are the signals that actually hold up under adversarial conditions.
  • Log UA for debugging, not gating. Recording the UA string in your access logs is useful for diagnosing compatibility issues. Using it to block or allow access is not.

The W3C frames user agents as actors that owe duties to end users: protection, honesty, and loyalty. That framing maps directly to ethical scraping. A scraper that misrepresents itself to bypass access controls is violating the spirit of those duties, and increasingly the letter of site terms of service. UA spoofing for the purpose of circumventing access controls carries policy risk; in some contexts, it may also carry legal risk under the Computer Fraud and Abuse Act. Consult qualified legal counsel for your specific situation.

Maintaining your UA list is not optional. Browsers release major versions every four to six weeks. A static list from six months ago will contain strings that no real user sends, which makes them statistically anomalous to any detection system that models real traffic distributions.

Infographic showing best practices for user-agent handling

Pro Tip: Schedule a monthly review of your UA list against a source like WhatIsMyBrowser or the pzb/user-agents gist. Strings that have aged out of real-world distribution are worse than no rotation at all because they create a fingerprint that matches nothing in the wild.


A checklist for reliable scraping: TLS, HTTP/2, and signal consistency

UA rotation alone does not make a scraper reliable. Modern WAFs operate on a stack of signals, and the UA string sits near the bottom of that priority order. Here is the operational checklist, ordered by impact:

  1. Use real browser engines or managed browser stacks. Puppeteer and Playwright with a real Chrome binary produce a TLS ClientHello that matches actual Chrome traffic. Standard HTTP libraries (python-requests, Go net/http, curl) do not, regardless of what UA string you attach.

  2. Match the TLS ClientHello (JA3/JA4). The JA3 hash encodes cipher suites, TLS extensions, elliptic curves, and compression methods. A Python OpenSSL ClientHello has a distinct JA3 that no browser produces. If your UA claims Chrome but your JA3 says Python, detection happens in milliseconds. Tools like curl-impersonate replicate the TLS and HTTP/2 stack of specific browser versions for exactly this reason.

  3. Match HTTP/2 header and frame ordering. HTTP/2 clients send SETTINGS and HEADERS frames in an order that is characteristic of the implementation. Chrome's HTTP/2 fingerprint differs from Firefox's, and both differ from Go's. Server-side tools can detect the implementation from frame ordering alone.

  4. Align runtime JavaScript APIs with the claimed UA. If your headless browser claims to be Chrome 124 but navigator.plugins is empty, window.chrome is undefined, or WebGL returns a software renderer string, detection scripts will flag the mismatch. Libraries like puppeteer-extra-plugin-stealth patch some of these, but coverage is incomplete.

  5. Avoid unique or fake hardware fingerprints. Canvas fingerprints, WebGL renderer strings, and audio context outputs should match plausible real-world values for the claimed device. Randomizing these values creates a unique fingerprint that appears in no real traffic distribution, which is a stronger detection signal than any known bot pattern.

The core principle: A reliable scraper is consistent, not clever. Every signal it emits — UA, TLS, HTTP/2, JS APIs, hardware fingerprints — should tell the same coherent story. One inconsistency is enough for a well-tuned WAF to flag the session. Chasing novelty by randomizing signals makes the problem worse, not better.

Tool options by fidelity level:

ApproachTLS fidelityJS API fidelityMaintenance burden
Real Chrome via PlaywrightHighHighMedium
curl-impersonateHighNone (no JS)Low
Puppeteer + stealth pluginMediumMediumMedium
python-requests + custom UANoneNoneLow (but detectable)
Go net/http + custom UANoneNoneLow (but detectable)

For teams building AI agent web browsing pipelines, the checklist above applies at every fetch call. An agent that issues hundreds of requests per session needs consistent signal alignment across the entire session, not just the first request.

Pro Tip: Record UA, JA3 hash, and HTTP/2 fingerprint together in your request logs. When a scraping session starts failing, that trio tells you immediately whether the issue is a UA mismatch, a TLS stack change after a library update, or a server-side rule change. Logging only the UA leaves you debugging blind.


Key Takeaways

A user-agent string is a client-controlled claim, not a verified identity. Reliable web data collection requires aligning UA, TLS, HTTP/2, and runtime signals into a consistent, coherent profile.

PointDetails
UA is a claim, not proofNever use the User-Agent header as the sole basis for a security or access decision.
Feature detection beats UA sniffingCheck for API existence directly; UA-based feature gating breaks on reduced strings and new browsers.
TLS/JA3 outranks UA for detectionWAFs read the TLS ClientHello before the UA string; mismatched stacks trigger blocks regardless of UA.
Keep your UA list currentBrowsers release major versions every 4–6 weeks; stale strings create anomalous fingerprints.
Gyrence removes the UA management burdenGyrence's managed Fetch and Extract primitives handle browser stack consistency so your pipeline doesn't depend on fragile UA rotation.

Why honest agent behavior beats constant spoofing

The scraping community spends enormous energy on UA rotation, stealth patches, and fingerprint evasion. Most of that energy is reactive: a WAF tightens a rule, scrapers adapt, the WAF updates again. It is an arms race with no stable equilibrium.

The more durable approach is to build scrapers that behave like honest agents. The W3C's framing of user agents as actors with duties to end users is not just an accessibility principle. It is a useful engineering constraint. A scraper that accurately represents what it is, respects rate limits, and surfaces its failures cleanly is easier to maintain, easier to debug, and less likely to trigger escalating countermeasures.

Gyrence's design reflects that philosophy directly. The five primitives (Search, Traverse, Fetch, Extract, Map) return typed, discriminated-union responses that include failure cases. When a fetch fails because a page returned a 429 or a bot challenge, the response says so explicitly. You do not get a silent empty result that looks like success. That transparency is what lets AI agents reason about web data rather than guess.

The practical implication: teams that invest in honest, maintainable agent behavior spend less time on evasion and more time on the actual data problem. UA spoofing is a symptom of a deeper issue, which is that the scraping stack is not aligned with the signals the server expects. Fix the stack, and the UA question becomes much less urgent.


Gyrence handles the browser stack so you don't have to

The UA rotation problem is really a signal-consistency problem. Every fix you apply at the UA layer exposes a new mismatch at the TLS or HTTP/2 layer. Gyrence sidesteps that cycle entirely.

Gyrence

Gyrence's Fetch primitive uses managed browser infrastructure with consistent TLS and HTTP/2 profiles. You send a URL; you get back clean, normalized markdown or structured JSON. No UA string to maintain, no JA3 mismatch to debug, no silent failures when a page returns a bot challenge. The Extract primitive adds LLM-powered schema-guided JSON extraction in the same call, with no separate AI billing line. Spending caps mean your data bill is predictable even when an agent loops unexpectedly.

For teams building at scale, the web scraping API handles browser-level signal consistency as a managed service. Start with the free tier at gyrence.com and make your first fetch in under five minutes.


Useful sources and parsing resources

On the nature of UA strings: The HTTP User-Agent header "is a characteristic string that lets servers and network peers identify the application, operating system, vendor, and/or version of the requesting user agent" — but it is self-reported and unverified by design. Every downstream use of UA data should account for that constraint.

Standards and primary references:

Security and detection research:

Databases and parsing tools:

  • ua-parser-js — (npmjs.org): JavaScript UA parser for browser and Node.js environments; returns structured browser, OS, and device objects.

FAQ

What are some common user-agent strings?

The most common desktop UA strings come from Chrome on Windows (Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ... Chrome/124.0.0.0 Safari/537.36), Firefox on Windows (Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0), and Safari on macOS (Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 ... Version/17.4.1 Safari/605.1.15). Automation clients like curl (curl/8.7.1) and python-requests (python-requests/2.31.0) use their library name and version by default.

How do I find my current user-agent string?

Open your browser's DevTools (F12), go to the Network tab, reload the page, click any request, and look for User-Agent under Request Headers. Alternatively, run console.log(navigator.userAgent) in the browser console, or use curl -I https://httpbin.org/user-agent from the command line.

What is an example of a user-agent string?

A typical Chrome 124 desktop string 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. The Mozilla/5.0 prefix is a legacy compatibility token; the actual browser identity is in the Chrome/124.0.0.0 token at the end.

What is the best user-agent to use for web scraping?

For scraping that needs to pass WAF inspection, the UA string matters less than the TLS and HTTP/2 fingerprint. Use a real Chrome binary via Playwright or Puppeteer so the full signal stack (UA, JA3, HTTP/2 frames) is consistent. For simple, non-protected endpoints, a current Chrome desktop UA string works fine. Gyrence's Fetch primitive handles browser-level signal consistency as a managed service, removing the need to maintain UA strings manually.

Why does Chrome always show 0.0.0 as the minor version?

Chrome's UA reduction policy freezes the minor, build, and patch version numbers at 0.0.0 in the UA string. The full version is only available through Sec-CH-UA-Full-Version-List, a Client Hints header that requires the server to request it via Accept-CH. This is intentional: it reduces passive fingerprinting surface while still allowing servers to request precise version data when they need it.