quest_ai_browsers_ga4_atlas_comet.exe
_
×

AI Browsers in GA4: How to Detect Atlas and Comet Sessions

Your Atlas and Comet sessions are already in GA4, disguised as Chrome. A practitioner's method to detect AI browser traffic server-side and quantify it.

ga4 ai-browsers server-side gtm analytics guide

Your AI browser sessions are already in GA4, and they are posing as Chrome. Comet and ChatGPT-style agents send no distinctive user-agent on the page render, refuse or block tracking by default, and break session continuity. The result: “new users” who are nothing of the sort, Direct traffic that swells with no campaign behind it, and zero-engagement sessions that drag down your averages. The problem is not that the data is wrong. It is that nobody measures what they are losing, because nobody knows how to spot these sessions.

A quick point on vocabulary, because everyone has been conflating two things for six months. There is traffic coming from an AI (someone clicks a link inside a ChatGPT or Perplexity answer, which is a channel attribution problem, covered in Track AI traffic in GA4). And there is traffic driven by an AI: the agent IS the browser. That is what we are dealing with here, and it is a data quality problem, not an attribution one.

A word on timing, because this moves fast. OpenAI shut down the standalone ChatGPT Atlas app on August 9, 2026, nine months after launch. Do not file the topic away, though. The Atlas sessions from the past few months are still in your GA4 history and are polluting your comparisons, its agent capabilities have moved into the ChatGPT Chrome extension, the desktop app, and a cloud-hosted remote browser, and above all Comet is climbing. In July 2026, Comet accounted for roughly 47% of agentic traffic measured by HUMAN Security, the Claude for Chrome extension around 24%, and Atlas about 15.5% and falling. The Atlas brand is fading; the category is exploding.

Three symptoms to check in GA4 in five minutes

Before the theory, the diagnosis. Open GA4 and look at three things.

First, the new-users curve over the last 90 days. A step up with no campaign, no seasonal peak, nothing to explain it, is your first signal. Agents do not persist cookies between runs: every visit starts from scratch, so every visit is a “new user”.

Next, the share of Direct. An agent that opens your page with no referrer lands in the Direct bucket like any other origin-less hit. If your Direct is rising while your brand awareness has not budged, be suspicious.

Finally, median engagement time by device and browser. Compare macOS desktop to your other segments. An agentic session reads the DOM in a few hundred milliseconds and leaves: it pulls down the engagement average of whatever segment it hides in. If you see a desktop segment with abnormally low engagement, you have your lead. To separate this noise from a genuine configuration issue (internal traffic, duplicates, unassigned), first run your property through the GA4 audit checklist.

Why it is invisible: what each browser does

The reason your standard reports see nothing is that every AI browser sabotages tracking at a different point in the chain. Here is the behavior observed on the main players.

BehaviorComet (Perplexity)ChatGPT agent / ex-AtlasClaude for Chrome
User-agent on page renderStandard ChromeStandard ChromeStandard Chrome
Distinctive signatureRare, possible perplexity.ai referrerCFNetwork/Darwin on favicon fetchExtension, inherits host Chrome
Ad blocker by defaultYes, blocks GA4 and GTMNo, but isolated contextNo
ConsentVariable behaviorFrequently rejects bannersDepends on user
Referrer passedOften preservedOften absentVariable
Client-side GA4 visibilityNone if adblock onPartialGood

The line that hurts is the ad blocker row for Comet: its built-in blocker filters analytics scripts by default. When a user visits your site through Comet with blocking on, you often see nothing at all client-side. Not a truncated session, zero session. Conversely, Comet frequently passes the perplexity.ai referrer, so part of its traffic still shows up as referral. So you have two Comet populations: the one that goes through the classic GA4 tag, and the one entirely absent from your client-side reports.

For the Atlas-heir agent, the trap is subtler. Page content loads through a Chrome instance with a perfectly normal user-agent. Only the favicon and logo fetch goes out with the ChatGPT Atlas/… CFNetwork/… Darwin/… signature. In other words, the proof exists, but not where you look for it: it is in your server logs, on a side request, not in the main GA4 hit.

Interim conclusion: every usable signal lives at the server layer. The client side is blind by design. That is why serious detection runs through a server-side container.

Detect: server-side signals and the ai_browser dimension

If you do not have a server-side GTM container yet, that is the prerequisite, and it is covered in Migrate to server-side GTM. The idea: instead of trusting the browser, you inspect the request as it arrives at your collection endpoint, where the headers survive.

Three families of signals are usable.

Client Hints first. The sec-ch-ua header and its variants expose the engine brand and version. A mismatch between what the user-agent declares and what the Client Hints say is a classic marker of an automated environment. Add sec-ch-ua-platform and sec-ch-ua-mobile to sharpen it.

The network signature next. On side requests, the CFNetwork string paired with Darwin betrays a native macOS application that is not a classic browser. On its own it proves nothing. Crossed with a navigation pattern (a single page, no scroll, near-zero time on page, no heavy asset request), it becomes a strong indicator.

Behavioral patterns last. No referrer on a macOS desktop session, an overly regular event sequence, a total absence of interaction. None of these signals is enough alone. It is their accumulation that makes the detection, which is why we call it a heuristic, not a certainty.

In your sGTM container, you set a variable that evaluates these signals and writes an ai_browser custom dimension onto the event before forwarding it to GA4. Here is the logic, as custom-variable pseudo-code (Sandboxed JavaScript):

// sGTM custom variable: classify the incoming request
const getHeader = require('getRequestHeader');
const ua = getHeader('user-agent') || '';
const chUa = getHeader('sec-ch-ua') || '';
const referer = getHeader('referer') || '';

// 1. Native macOS signature outside a classic browser
if (ua.indexOf('CFNetwork') !== -1 && ua.indexOf('Darwin') !== -1) {
  return 'chatgpt_atlas';
}
// 2. Perplexity marker preserved in the referrer
if (referer.indexOf('perplexity.ai') !== -1) {
  return 'comet_or_perplexity';
}
// 3. Client Hints / user-agent mismatch (heuristic)
if (ua.indexOf('Chrome') !== -1 && chUa === '') {
  return 'suspect_headless';
}
return 'human';

You then map the returned value to an ai_browser event parameter, registered as a custom dimension in the GA4 interface. From there, every session is labeled, and you can segment instead of suffer. One caveat: this code is a baseline to harden, because the signatures change, as we will see below.

Quantify: measuring the distortion in BigQuery

A dimension is good. A number you can put on the table in front of a client or a steering committee is better. If the BigQuery export is not on, wire it up, then borrow from the essential BigQuery queries for GA4. The query below measures the gap between presumed human traffic and suspect traffic across three metrics that speak: session share, new-versus-returning ratio, and median engagement time.

SELECT
  COALESCE(
    (SELECT value.string_value FROM UNNEST(event_params)
     WHERE key = 'ai_browser'), 'human') AS bucket,
  COUNT(DISTINCT CONCAT(user_pseudo_id,
    (SELECT value.int_value FROM UNNEST(event_params)
     WHERE key = 'ga_session_id'))) AS sessions,
  ROUND(AVG(
    (SELECT value.int_value FROM UNNEST(event_params)
     WHERE key = 'engagement_time_msec')) / 1000, 1) AS avg_engagement_s
FROM `your_project.analytics_XXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260601' AND '20260831'
GROUP BY bucket
ORDER BY sessions DESC;

What you are looking for: a chatgpt_atlas or comet_or_perplexity bucket with floor-level engagement time and a volume that is not negligible. The day you put a percentage on it (“4% of our sessions are agents, with engagement ten times lower”), the topic moves from curiosity to decision.

Decide: filter, segment, or keep?

Here is my take, and it takes a side: do not filter blindly. The temptation is to build a GA4 filter that excludes everything tagged ai_browser and move on. In most cases, that is a mistake.

An agent-driven session is very often a pre-purchase research session launched by a human. Someone asks their assistant to compare three products, the agent visits your page, pulls the price and specs, and reports back to the human who decides. Deleting that session means losing a signal of real demand. Worse, when the agent goes all the way to purchase, you want to measure it, not erase it, and that is the whole point of agentic commerce in GA4.

My recommendation, in order:

  1. Segment first. Keep the data, isolate it with the ai_browser dimension. Your “human” reports become clean again without throwing anything away.
  2. Filter next, and only clearly autonomous traffic. An agent that loops, that scans without ever converting, that has no analytical value: there, yes, an exclusion audience is justified.
  3. Keep a raw copy in parallel. An unfiltered property or stream is your reference so you are not flying blind.

One point on consent. The former Atlas frequently rejected banners, and Comet blocks part of the analytics stack. Concretely, a large share of this traffic lands as denied on the Consent Mode side, which feeds conversion modeling rather than direct measurement. If you do not yet understand how that shift affects your numbers, Consent Mode v2 in GA4 covers the basics. Treating agents as humans without consent distorts your models twice over.

The honest limits

I am not going to sell you perfect detection, because it does not exist.

The method is heuristic. You work on bundles of clues, not an official label. You will get false positives (a genuine macOS user with an aggressive ad blocker) and false negatives (a well-disguised agent that passes for human).

The signatures change. CFNetwork/Darwin works today because the implementation lets it leak. The next version might route that fetch differently, and your rule falls over. This is maintenance, not “set and forget”.

And Comet in blocking mode stays invisible. If it cuts GA4 and GTM at load time, no signal reaches your container, server-side included, because the tag never fires. The only reliable countermeasure is analyzing your raw server logs, outside GA4. That is a separate project.

One last structural reminder: every new client-side signal that disappears strengthens the server-first case. AI browsers are just one more symptom of that shift, in the same vein as the end of Privacy Sandbox. If your measurement still depends entirely on the browser in 2026, agents are not your real problem.

Actionable recap

Open GA4, check the three symptoms (new users stepping up, Direct swelling, macOS desktop engagement abnormally low). If it matches, set an ai_browser dimension in your server-side container from the header signals, quantify the distortion with the BigQuery query, then segment before you filter anything. Keep in mind that the Atlas brand is disappearing but the category, Comet in front, is only getting started. The data you clean today is the data you will steer your budgets on tomorrow.