The AI traffic channel you set up in an earlier post classifies your acquisition. To segment, compare, and build audiences you need more: flag the session with a custom event, its parameters, and its dimensions. Here you build it step by step.
The distinction matters. The channel setup groups where the session came from — acquisition, by configuring a regex over the referrer. A custom event lets you flag your users' sessions inside Google Analytics 4 (GA4) for explorations, comparisons, and audiences — and it can use signals that merely identifying the channel they came from doesn't consider, such as the landing page or a UTM tag.
The root problem is still the one that opened this series of posts: a good share of AI traffic hides as Direct. We already covered the server layer; this guide closes the pair with the client-side layer.
Channel vs. Custom Event: When the Channel Isn't Enough
The custom channel classifies each session by its source — it's an acquisition view, and it's excellent at that. What it doesn't do: it won't flag sessions by landing page or arbitrary URL parameters, and the channel dimension isn't always convenient for audiences or granular explorations in custom reports.
According to Google, custom events let you collect information that GA4 doesn't collect on its own — you define the name, the parameters, and the condition that fires it. You choose the signal, not the channel group.
There's also a time asymmetry worth knowing before you start. According to Google, custom channel groups apply retroactively to historical data; an event, by contrast, only exists from the moment you implement it — and according to Google, its dimensions only fill with data collected after registration. Every week without your event configured is historical information you won't get back — implement it as soon as you can.
Subscribe to the Madbotz newsletter to get the next analysis straight to your inbox. No spam, no noise — just new posts.
The Signals That Give Away an AI Session
On the client side there are three usable signals — and one no-signal case. The first is the referrer read by JavaScript: according to MDN, document.referrer returns the URI of the page that linked to the current one, so it's enough to compare it against a list of assistant domains. The list is the same one that lives in the channel's regex — no need to duplicate it.
The second is the UTM tag some sources add on their own. According to Search Engine Roundtable, OpenAI appends utm_source=chatgpt.com to ChatGPT's outbound links and extended that tagging to more links in 2025 to improve measurement. It's a precise signal as long as the source keeps it — if the format changes, your detection changes with it.
The third signal is the telltale landing page: a URL almost nobody finds through Google or social because it only circulates in AI answers — for example, a landing page you created for assistants to cite. If a session lands exactly there, odds are it came from an assistant. It's a supporting signal: use it to reinforce the referrer or the UTM, not as the only evidence.
Table 1 — signals for detecting an AI session on the client side. The last column, "Reliability — when to use it," is each signal's short answer.
| Signal | Where it's read | How it fires the event | Reliability — when to use it |
|---|---|---|---|
| Referrer (document.referrer) | JavaScript in the browser | GTM variable compared against the list of AI domains | High when the source passes a referrer (Perplexity, Gemini, Copilot…) |
| UTM and URL parameters | The landing page URL | Trigger on the query parameter (utm_source=chatgpt.com) | High when the source adds them — fragile if the format changes |
| Landing page | The user's landing path | Trigger on the URL path | Medium — supporting signal; combine it with referrer or UTM |
| No signal (Atlas and similar) | Nothing to read on the client side | Cannot fire | Zero client-side — server layer |
The fourth case — no signal — can't be flagged from the browser; we come back to it at the end of this guide.
Build the ai_session Event (Steps 1-3)
Six steps in total, in two blocks: build the event (1-3) and take it from parameter to report (4-6).
Step 1: Define the Event Taxonomy
Our suggestion: an ai_session event with two parameters — ai_source (chatgpt, perplexity, gemini, copilot…) and ai_detection_method (referrer, utm, landing). The naming is our own convention, not a GA4 standard — name it however you like as long as you follow the naming rules. According to Google, event names must be under 40 characters, start with a letter, and use only letters, numbers, and underscores.
Parameters have a limit too. According to Google, each event allows up to 25 parameters and most values are cut at 100 characters — plenty for a two-parameter taxonomy, but worth knowing before you grow.
Step 2: Implement Detection in GTM or gtag
With Google Tag Manager (GTM), detection lives in a custom JavaScript variable — a reusable piece GTM runs on every page to compute a value, which you'll later use as a condition in your triggers. To create it, go to tagmanager.google.com, open your site's container, and go to Variables in the side menu. Under "User-Defined Variables" click New, choose the "Custom JavaScript" type, name it — for example, JS - ai_detection_method — and paste this code:
// GTM variable — returns the detection method or 'none'
function() {
var aiSources = /chatgpt\.com|perplexity\.ai|gemini\.google\.com|claude\.ai|copilot\.microsoft\.com/;
if (aiSources.test(document.referrer)) return 'referrer';
var utm = new URLSearchParams(location.search).get('utm_source') || '';
if (aiSources.test(utm)) return 'utm';
return 'none';
}
This is an illustrative example, not a full implementation — the complete domain list lives in the channel's regex and it's best to keep it in a single place so you don't maintain two lists. Repeat the process for a twin variable that returns the source (chatgpt, perplexity…) instead of the method — you'll use it to fill the ai_source parameter.
Without GTM, the same logic works with gtag directly in your template:
// gtag — fire the event only when there's a signal
if (method !== 'none') {
gtag('event', 'ai_session', {
ai_source: source,
ai_detection_method: method
});
}
Step 3: Fire the Event on the First Page View
The event must go out on the landing page — that's where the signal lives. In GTM that takes two pieces: a tag that sends the event and a trigger that decides when to fire it.
First the tag: in the side menu go to Tags → New and choose the "Google Analytics: GA4 Event" type. Enter ai_session as the event name and add the two parameters, filling each value with the Step 2 variables — ai_detection_method with {{JS - ai_detection_method}} and ai_source with {{JS - ai_source}}.
Now the trigger: under Triggers → New choose the "Page View" type. According to Google, page view triggers fire when the browser begins to load a page. Select "Some Page Views" and set the condition: {{JS - ai_detection_method}} does not equal none — so the tag only fires when there's an AI signal.
The detail that matters: the referrer only exists on the entry page. If you wait for the second page view, the signal is gone — that's why the trigger goes on the session's first page view. Assign the trigger to the tag, save, and publish the container.
From Parameter to Report: Register, Validate, Exploit (Steps 4-6)
Step 4: Register the Custom Dimensions
The step almost everyone forgets. GA4 collects your event's parameters from the very first fire, but shows them in no report until you tell it they exist — that's registering them as custom dimensions. Without this registration, ai_source reaches GA4 with every event and still shows up nowhere.
According to Google, registration happens in Admin → Data display → Custom definitions → Create custom dimension. You fill in three fields: the dimension's display name (for example, "AI Source"), the scope — choose Event (event-scoped), because the parameter travels in an event — and the event parameter, typed exactly as it arrives: ai_source, capitalization included. A one-letter mismatch produces empty values with no visible error.
Repeat the process for the second dimension: "AI Detection Method" on ai_detection_method. They're two one-time registrations — two minutes of work separating an invisible event from an exploitable one.
Two limits that matter from that same documentation: a standard property allows up to 50 event-scoped custom dimensions, and values only fill for data collected after registration — history is not backfilled. According to Simo Ahava, parameters that exceed the quotas still pass through to the BigQuery export — a lifesaver if you register late, but not a substitute for doing it on time.
Step 5: Validate in DebugView and Realtime
DebugView is GA4's live inspector: it shows, hit by hit, the events arriving from a browser in debug mode. You'll find it under Admin → Data display → DebugView, and the simplest way to enable it is GTM's Preview mode — when you enter your site from there, your visits are automatically flagged as debuggable.
Now simulate the visit: in that same preview window, open your site with ?utm_source=chatgpt.com appended to the URL — or arrive from a real assistant. ai_session should appear in the DebugView timeline; click the event and verify it carries both parameters with the expected values (ai_detection_method: utm, ai_source: chatgpt).
Second check in Reports → Realtime: look for ai_session in the events card and confirm the count rises with each simulated visit. DebugView validates the detail of one visit; Realtime validates that the full flow reaches the property.
If the parameter arrives empty or as (not set), review the Step 4 registration. And be patient with standard reports: data for a freshly registered dimension can take up to 48 hours to appear — not showing up in a report today doesn't mean the event is broken.
Step 6: Exploit the Dimension in Reports and Audiences
Here's the return on the whole build: three uses, each with its business question.
Explorations — GA4's analysis lab. Go to Explore, create a blank exploration, and add "AI Source" as a dimension next to your usual metrics (sessions, conversions, revenue). Answer: which assistant brings me the most sessions, and what do those visits do on the site?
Comparisons — filters overlaid on your standard reports. In any report, click Add comparison and create one with the condition "AI Detection Method" not equal to (not set) — that is, sessions flagged by the event — alongside another with all users. Answer: does AI traffic behave differently from my organic traffic?
Audiences — reusable user groups for reports and campaigns. In Admin → Audiences, create a new one with the condition of having fired ai_session; GA4 fills it from that moment on. Answer: how do I analyze — or re-engage — the people who arrived from an assistant?
What It Actually Flags — and What It Doesn't
Honesty before hype — the same rule we applied to the channel. The event flags the sessions that leave some signal: referrer, UTM, or landing page. It helps you flag; it doesn't guarantee identifying 100% of AI traffic.
If the browser sends nothing, the client side is blind. According to MDN, document.referrer returns an empty string when no page linked over — and ChatGPT Atlas is exactly that case: no referrer and no UTM means no condition to evaluate and no event to fire.
That traffic is handled in the server layer we already covered in this series. The bridge is direct: the Measurement Protocol can fire the same ai_session event from your server, with the same taxonomy — client and server feed a single dimension.
How We Use It at Madbotz — and a Privacy Note
The privacy note — brief but not optional. According to Google, sending personally identifiable information (PII) to Analytics is prohibited — no emails, names, or personal identifiers in your parameters. A taxonomy like ai_source=chatgpt touches no personal data, but if your detection grows toward identifiers, Mexico's LFPDPPP (Federal Law on the Protection of Personal Data Held by Private Parties) and Europe's GDPR (General Data Protection Regulation) come into play — and that's for your legal team to validate, not your GTM container. AI measurement privacy deserves its own post; it's on the list.
Frequently Asked Questions
Does the custom event replace GA4's AI channel?
No — they complement each other. The channel groups where the session came from in your acquisition reports; the event flags the session with your own parameters for explorations, comparisons, and audiences, and can use signals the channel doesn't consider, such as the landing page.
Can I flag ChatGPT Atlas traffic with a custom event?
Only if it leaves some signal. Atlas passes no referrer and its visits carry no UTM, so there is nothing to detect on the client side. That traffic is handled with server-side measurement, as we explained in the server-side post of this series.
Why don't I see my parameters in GA4 reports?
Almost always because the custom dimension isn't registered in Admin → Custom definitions. Without that registration the parameters are collected but never show up in reports, and after registering, data can take up to 48 hours to appear.
Does the event flag past sessions?
No. An event only exists from the moment you implement it, and its dimensions only fill with data collected after registration. That's the asymmetry with custom channel groups, which do apply retroactively to historical data.
Wrapping Up
The ai_session event is this series' granularity piece: the channel tells you where the traffic came from; the event lets you segment it, compare it, and turn it into audiences.
Three ideas to take with you:
- The channel groups acquisition; the event flags the session — they complement each other, they don't compete.
- The step almost everyone forgets is registering the dimensions: without registration, parameters are collected but never seen.
- Events are not retroactive: every week without them is history you lose.
And the cause before the measurement: AI sessions are born from your presence in the models' answers. Before fine-tuning the flagging, make sure AI sees you and cites you — you measure that with the AI Visibility Score, the same 130+ check item engine we run on our own site.