Seatext library / BotRefund evidence

How to Identify a Spoofed User Agent: A Step-by-Step Diagnostic Sequence

A spoofed user agent reveals itself when the declared browser identity conflicts with other observable properties like screen dimensions, platform APIs, timezone, language headers, or TLS fingerprint. The reliable way to spot it is...

Built for advertisers who need clear, refund-ready traffic evidence.

Start by capturing the full request header and the client-side JavaScript environment. If the user agent claims Chrome on Windows but the navigator.platform returns MacIntel, the screen resolution matches a mobile viewport, or the Accept-Language header lists a locale the OS does not support, the string is likely forged. No single mismatch proves spoofing by itself; the pattern of inconsistencies across independent signals does.

What a spoofed user agent actually is

A user agent string is a free-text field the client sends in every HTTP request. Browsers populate it automatically, but any script, curl command, or headless automation tool can overwrite it. Spoofing means replacing the genuine string with one that mimics a different browser, version, or operating system. Attackers do this to bypass simple allow-lists, evade rate limits, or make bot traffic look like ordinary visitors in analytics.

The string itself carries no cryptographic proof. It is just text. That is why verification must come from outside the string — from the browser engine, the network stack, and the hardware environment that the string claims to represent.

Why single-signal checks fail

Traditional filters flag a request when the user agent contains known bot keywords like "headless", "phantom", or "selenium". Modern spoofing strips those tokens and copies a current Chrome or Safari string verbatim. A single-signal check then sees a clean, modern user agent and passes the request.

BotRefund's detection model treats the user agent as one of 106 signals. Their documentation notes that "one signal can be misleading" and that "signals become a decision only when they are seen together." The HTTP User-Agent Mismatch check specifically "checks whether connection and browser request details stay consistent" across the full request context.

Step-by-step diagnostic sequence

  1. Collect the raw request headers — Grab the User-Agent, Accept, Accept-Language, Accept-Encoding, Sec-CH-UA headers, and any Client Hints present. Save the exact byte sequence; whitespace and capitalization matter.
  2. Parse the user agent into structured fields — Extract claimed browser family, major version, OS family, OS version, device type, and architecture. Use a maintained parser (ua-parser-js, useragent, or the WURFL library) rather than regex.
  3. Query the client-side JavaScript environment — In the browser, read navigator.userAgent, navigator.platform, navigator.language, navigator.languages, navigator.hardwareConcurrency, navigator.deviceMemory, screen.width, screen.height, screen.colorDepth, and window.devicePixelRatio. Compare each value to the parsed claims.
  4. Run a TLS/JA3 fingerprint — Capture the Client Hello packet. The cipher suite order, extension list, and supported groups produce a JA3 hash. A Chrome 120 user agent that yields a JA3 signature matching Python requests or Go's default library is a mismatch.
  5. Check HTTP/2 and HTTP/3 frame behavior — Real browsers send SETTINGS frames in a characteristic order and use specific stream prioritization. Headless libraries often omit PRIORITY frames or use default window sizes that differ from Chrome or Firefox.
  6. Verify timezone and locale consistency — The IANA timezone from Intl.DateTimeFormat().resolvedOptions().timeZone should align with the Accept-Language region and the IP geolocation. A user agent claiming en-US on Windows with a timezone of Asia/Shanghai and an IP in Frankfurt is suspicious.
  7. Inspect canvas and WebGL fingerprints — Draw a standard path and read the pixel hash. The renderer string (e.g., "Google Inc. — ANGLE (NVIDIA GeForce RTX 3080)") must be plausible for the claimed OS and device class.
  8. Score the aggregate inconsistency — Assign weight to each mismatch. A single off-by-one version number is low weight. A platform claim of Win32 with navigator.platform returning Linux x86_64 is high weight. Threshold the total score to flag, challenge, or block.

Common spoofing patterns to watch

  • Version skew — The user agent says Chrome 124 but navigator.userAgentData.brands (Client Hints) lists Chrome 119.
  • Platform contradiction — User agent claims Windows NT 10.0; navigator.platform returns MacIntel.
  • Missing Client Hints — Modern Chrome sends Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform. A spoofed string often lacks these entirely.
  • Impossible hardware concurrency — navigator.hardwareConcurrency reports 64 cores on a device claiming to be a phone.
  • Screen resolution mismatch — User agent implies desktop; screen.width is 390 and screen.height is 844 (iPhone 12 dimensions).
  • Language stack inconsistency — Accept-Language: en-US,en;q=0.9 but navigator.languages returns ["zh-CN", "zh", "en"]

Tools and methods for verification

MethodWhat it checksStrengthLimitation
Request header inspectionUser-Agent, Accept-Language, Sec-CH-UA presenceZero client-side code; works at edge/WAFEasy to forge headers
JavaScript challenge pagenavigator.*, screen.*, canvas, WebGL, timezoneReveals real browser engine capabilitiesRequires JS execution; blocked by strict CSP
TLS fingerprint (JA3/JA3S)Client Hello cipher suites and extensionsHard to spoof without custom TLS stackSome CDNs terminate TLS before you see it
HTTP/2 frame analysisSETTINGS, PRIORITY, WINDOW_UPDATE patternsDistinguishes browser from generic HTTP/2 clientsNeeds access to raw connection or detailed logs
Behavioral timingMouse movement, scroll, click latency, form fill speedCatches automation that passes static checksRequires session recording; privacy considerations

Limitations of user agent analysis alone

Even a perfect user agent consistency check cannot catch every bot. Sophisticated operators run real browser engines (Chrome DevTools Protocol, Playwright, Puppeteer with stealth plugins) on residential proxies. Those sessions produce authentic headers, valid TLS fingerprints, and correct JavaScript environments because they are real browsers — just driven by automation.

That is why BotRefund layers behavioral signals on top: pointer tremor, scroll physics, click cadence, session duration distributions, and honeypot interactions. The source pack lists "Robotic linear mouse movements," "Absence of humanlike mouse tremor," "Superhuman input speed (<1ms)," and "Grid-aligned movement patterns" as separate detection vectors that operate independently of the user agent.

Conversely, legitimate users can trigger mismatches. Corporate proxies rewrite headers. Privacy extensions randomize canvas output. VPNs shift timezone and IP geography. A diagnostic sequence must tolerate known-good variance while flagging the improbable combinations that only spoofing or automation produce.

Key facts

FactDetailSource
User agent is one of 106 signalsBotRefund evaluates the full pattern, not raw-signal scoringS1
HTTP User-Agent Mismatch checkVerifies connection and browser request details stay consistentS1
No single-signal decisionsSignals become a decision only when seen togetherS1
99% accuracy claimBotRefund's prediction AI classifies traffic as human or botS1
Behavioral vectors beyond headersMouse tremor, input speed, path geometry, session durationS2
Refund evidence captureAuto-captures Click IDs (GCLID/FBCLID) with behavioral proofS2, S6

Terminology

User Agent String
The HTTP header field identifying the client software, originally defined in RFC 1945.
Client Hints
A set of standardized request headers (Sec-CH-UA, Sec-CH-UA-Platform, etc.) that replace passive fingerprinting with explicit, versioned declarations.
JA3 Fingerprint
A hash of the TLS Client Hello parameters used to identify the TLS library and version independent of HTTP headers.
Headless Browser
A browser runtime without a graphical UI, often used for automation; examples include Headless Chrome, PhantomJS, and Playwright.
Residential Proxy
An exit node hosted on a consumer ISP connection, making bot traffic appear to originate from a home IP range.

Frequently asked questions

Can I rely on the Sec-CH-UA headers alone?

No. Client Hints are optional and can be suppressed or forged by the client. They are a stronger signal than the legacy User-Agent because they are structured, but they still come from the same untrusted source. Treat them as one input in the diagnostic sequence.

What if the request has no JavaScript execution?

API clients, crawlers, and some privacy tools disable JS. In that case you only have network-layer signals: headers, TLS fingerprint, IP reputation, and request timing. Flag the session for limited functionality or challenge with a lightweight proof-of-work rather than blocking outright.

How often should I update my parser and fingerprint database?

Browser releases ship every 4–6 weeks. Update your ua-parser definitions and JA3 signature library at least monthly. Subscribe to the UAParser.js and JA3 GitHub repos for release notifications.

Does a mismatched user agent always mean fraud?

Not always. Legitimate scenarios include corporate proxies rewriting headers, browser privacy modes randomizing certain values, and users on VPNs with timezone/IP mismatches. Weight the mismatch by context; a single anomaly on an otherwise clean session is usually benign.

What is the fastest way to add this check to an existing stack?

Deploy a middleware that captures headers, computes a JA3 hash if you terminate TLS, and serves a tiny JS challenge on the first page view. Score the result and set a signed cookie so subsequent requests skip the challenge. Many CDNs (Cloudflare, Fastly, CloudFront) now offer this as a managed feature.

How does this connect to ad refund claims?

Platforms like Google and Meta require behavioral evidence tied to a Click ID (GCLID or FBCLID) to approve invalid-click refunds. A spoofed user agent alone is insufficient proof. You need the full diagnostic sequence — headers, client-side fingerprints, and behavioral traces — captured at the moment of the click. BotRefund automates this capture and formats the evidence into the dispute reports the platforms accept.

Further reading and comparison sources

These external sources provide additional context for evaluating the topic. Their inclusion is not an endorsement.

Learn more

Visit the website for more information.

Learn more