User Agents in Analytics Debugging: GA4, Bot Traffic and Browser Bugs

When a conversion rate drops for one browser, sessions spike from a country you do not sell to, or events stop firing on iPhones, the user agent is usually the first clue. Analytics tools summarise it into "browser" and "device" dimensions and throw the raw string away, so debugging starts by getting the raw value back. After that come what it can prove and where it misleads.

Get the raw user agent next to the event

GA4 does not expose the full user-agent string in reports or in the BigQuery export. It keeps derived fields such as device.web_info.browser, device.web_info.browser_version, device.operating_system and device.category. That is fine for trends, and not enough when you need to see exactly which client broke.

Capture the raw value yourself when you debug. Send it as an event parameter from the page, or log it on the server beside the request that recorded the event. Server logs have the advantage of also showing requests from clients that never ran your tracking script.

// Temporary debugging parameter (register it as a custom dimension to see it)
gtag('event', 'checkout_error', {
  debug_ua: navigator.userAgent.slice(0, 100),   // GA4 limits parameter values to 100 chars
  error_code: code,
});

Keep such parameters temporary and document them. A user-agent string on its own is not personal data in most readings, but combined with other fields it contributes to fingerprinting. Your privacy notice and consent setup should cover what you collect.

Find the pattern: compare broken and healthy sessions

A tracking bug that affects every browser is a code bug. One that affects a single browser, version or platform shows up clearly once you split the data. Break the failing metric down by browser, browser version and operating system, and compare it with the same breakdown for a healthy metric over the same period.

-- BigQuery, GA4 export: purchases vs begin_checkout by browser version
SELECT
  device.web_info.browser          AS browser,
  device.web_info.browser_version  AS version,
  COUNTIF(event_name = 'begin_checkout') AS checkouts,
  COUNTIF(event_name = 'purchase')       AS purchases,
  SAFE_DIVIDE(COUNTIF(event_name = 'purchase'),
              COUNTIF(event_name = 'begin_checkout')) AS rate
FROM `project.analytics_123456.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260901' AND '20260927'
GROUP BY browser, version
HAVING checkouts > 50
ORDER BY rate

A version with a rate far below its neighbours points to a change in that release, such as a new storage restriction, a changed default or a broken polyfill. A drop across all Safari versions at once usually points to your own deploy, or to a change in Intelligent Tracking Prevention.

Common causes a user agent reveals

In-app browsers. Links opened from Instagram, Facebook, TikTok or LinkedIn load in an embedded web view whose user agent contains markers such as Instagram, FBAN/FBAV or LinkedInApp. These views often block third-party cookies, lose the session when the user switches to the real browser, and handle payment redirects badly. A checkout that fails mostly for these sessions is a classic finding.

Privacy features. Safari's Intelligent Tracking Prevention caps the lifetime of cookies set by script, Firefox's Enhanced Tracking Protection blocks known trackers, and Brave blocks many analytics scripts outright, sending a standard Chrome user agent while doing so. Missing sessions from these browsers often mean blocked scripts, not missing users.

Old or unusual engines. Smart TVs, games consoles, car browsers and older Android WebViews may not support the JavaScript your tag or site relies on. A cluster of errors from one old WebView version is common in markets with many older phones.

Emulated or automated clients. Headless Chrome identifies itself as HeadlessChrome unless configured otherwise. Lighthouse and PageSpeed Insights runs, uptime monitors and QA automation can all appear as real traffic if they execute your tags.

Separating bots from people

GA4 automatically excludes traffic from known bots and spiders, using Google research and the IAB/ABC International Spiders and Bots List. You cannot see how much was excluded or turn it off. What gets through are bots that execute JavaScript and do not declare themselves.

Signs in the data: sessions with near-zero engagement from a single browser version, an old Chrome release used long after it stopped receiving updates, a data-centre city, or a screen resolution that no real device has. Signs in server logs: many requests per second from one IP range, no requests for images or CSS, and user agents that claim a browser but lack the headers that browser always sends, such as Sec-CH-UA from Chrome.

Never trust a crawler's name in the user agent. Anyone can send Googlebot. Confirm it with a reverse DNS lookup (the hostname must end in googlebot.com or google.com), then a forward lookup of that hostname, which must return the same IP.

host 66.249.66.1
# 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.
host crawl-66-249-66-1.googlebot.com
# crawl-66-249-66-1.googlebot.com has address 66.249.66.1   <- matches: genuine

What UA reduction changed in your reports

Since Chrome's user-agent reduction, the string carries only the major version, and it reports a frozen Windows NT 10.0 and a fixed Android version and device model. Reports built on the classic string lose Windows 11, exact Android versions and phone models. That is why GA4 and other tools moved to User-Agent Client Hints for Chromium browsers.

If a report suddenly shows everyone on "Android 10" or cannot tell Windows 10 from 11, the data source is still parsing the classic string. Server-side parsers need the Sec-CH-UA-* headers, and for detail beyond the defaults they must request them with Accept-CH.

Remember when comparing periods: a sudden shift in reported OS versions around a Chrome release can be a measurement change, not a change in your audience.

Parsing user agents in logs

Do not write your own regex for browser detection. The strings are full of compatibility tokens: every Chromium browser also says Safari, and every Edge also says Chrome. Maintained libraries keep up with new formats: ua-parser-js for JavaScript, ua-parser (uap-core) for Python and several other languages, and matomo/device-detector for PHP.

# Top user agents in an nginx access log (combined format)
awk -F'"' '{print $6}' access.log | sort | uniq -c | sort -rn | head -20

Keep the raw string alongside the parsed fields. Parsers improve, and a value logged as "Unknown" today may be identified correctly after an update, but only if you still have the original.

A debugging record that others can reproduce

For each suspected client issue, write down the raw user agent, the Client Hints values if present, the date range, the affected metric and its baseline, and a step-by-step reproduction on a real device or an emulator with that user agent. Browser device emulation changes the user agent and viewport, but not the engine. A Safari bug must be reproduced in Safari, not in Chrome pretending to be an iPhone.

Sources and further reading

Google's Analytics Help documents the automatic known-bot exclusion and the GA4 BigQuery export schema. Google Search Central describes verifying Googlebot with reverse and forward DNS. The Chrome team's User-Agent reduction documentation and the WICG Client Hints specification describe the frozen fields. WebKit's blog documents Intelligent Tracking Prevention.

Frequently asked questions

Can I see the user agent in Google Analytics 4?

Not the raw string. GA4 reports and its BigQuery export contain parsed fields such as browser, browser version, operating system and device category. To debug with the full value, send it temporarily as a custom event parameter or read it from server logs.

Does Google Analytics filter bot traffic?

Yes. GA4 automatically excludes known bots and spiders using Google research and the IAB/ABC bots list, and this cannot be disabled or measured. Undeclared bots that run JavaScript can still get through.

How do I know if Googlebot in my logs is real?

Do a reverse DNS lookup of the IP; the name must end in `googlebot.com` or `google.com`. Then do a forward lookup of that name and confirm it returns the same IP. The user-agent string alone proves nothing.

Why do my reports show everyone on Android 10?

Chrome's user-agent reduction sends a fixed `Android 10; K` in the string. Tools that still parse the classic string report the frozen value; accurate data needs User-Agent Client Hints.

Why are sessions missing for Safari or Firefox users?

Their tracking protections can block or shorten analytics cookies and scripts. Compare server-side request counts per browser with analytics sessions to measure the gap.

What is an in-app browser user agent?

The embedded web view used when a link opens inside apps such as Instagram, Facebook or LinkedIn. Its user agent includes app markers like `Instagram` or `FBAV`, and it often has cookie and redirect limitations that break logins and checkouts.