All documentation

Analytics

AI traffic

Sessions that arrived from an AI engine, split by engine, with the pages they landed on and what they did next.

AI Traffic dashboard showing sessions by engine with referral trend sparklines, conversions, and top landing pages

What this is for

Citations record that an AI engine named your domain as a source for an answer. That measures the answer, not what the reader who saw it actually did. AI Traffic reads your Google Analytics 4 property for the sessions that arrived from an AI engine's own referrer, so you can see whether a citation turned into a visit, and whether that visit converted (api/routers/integrations.py#ai_traffic_summary). It is the outcome side of the same loop Google rankings versus AI citations opens on the input side: citations measure whether engines pull you in, AI Traffic measures whether the people they send you do anything once they land.

What counts as AI traffic

Every session GA4 logs carries a source, not always a referring host: it reads (direct) when there is none (api/services/integrations/google/ga4_attribution.py#_upsert_metrics). AI Traffic keeps only the sessions whose source matches one of 21 known AI referrer hosts, case-insensitively and regardless of scheme (https://chatgpt.com and chatgpt.com match the same way), each resolving to one of ten canonical engines: chatgpt.com, chat.openai.com and openai.com all resolve to ChatGPT; grok.com, x.ai and grok.x.ai all resolve to Grok; every other engine carries one to three hosts of its own (api/services/integrations/google/ga4_referrers.py#classify_referrer, #_AI_ENGINE_HOSTS). A session whose source is not on that list, including one with no referrer at all, is not counted here, whatever channel it actually came from. That classification is the only place in the product that decides whether a session is AI-referred; nothing else here duplicates it with a second definition.

Five of those ten referrers, ChatGPT, Claude, Gemini, Grok, and Perplexity, belong to engines the rest of the product runs prompts against, and they carry their usual logo here too. The ChatGPT referrer is named plain "ChatGPT": it counts people who arrived from ChatGPT itself (the three OpenAI hosts above), and the product's ChatGPT engine, ChatGPT (app), maps to it. The Gemini referrer is named plain "Gemini" in the same way: it counts people who arrived from Gemini's own hosts (gemini.google.com and bard.google.com), and both Gemini engines, Gemini (API) and Gemini (app), map to it. Google AI Overviews and Google AI Mode have no referrer of their own: a visit from either reaches GA4 as ordinary Google search traffic, which cannot be told apart from any other Google click, so neither appears here (api/services/integrations/google/ga4_referrers.py#REFERRER_BY_ENGINE). The other five, Copilot, You.com, Phind, Kagi, and Metaphor, are not engines DiscoveredBy queries directly, but GA4 still reports sessions from them, so they appear here with a title-cased name and a plain colour instead of a logo (frontend/src/lib/provider-meta.js#PROVIDER_META).

What you see

The hero number is total sessions for the window, with a breakdown by engine underneath, each row carrying its share of the window's traffic and, where that engine also had traffic in the prior window to compare against, a change figure; an engine appearing for the first time shows no change at all rather than a percentage measured from zero (api/services/integrations/google/ai_referral_metrics.py#engine_summary, frontend/src/lib/components/DeltaChip.svelte#delta). The filter bar's engine chip narrows every figure on the screen to the visits that engine's assistant sent, by the referrer classification above: ChatGPT (app) to the ChatGPT referrer, either Gemini engine to the one Gemini referrer, so Gemini (API) and Gemini (app) show the same Gemini visits, Claude to Claude's, and likewise for Grok and Perplexity (api/services/integrations/google/ai_traffic.py#referral_conditions, api/routers/integrations.py#AI_TRAFFIC_ACCEPTS). When that engine sent nothing in the window, the screen says so and offers Show all engines. Choosing Google AI Overviews or Google AI Mode always reads that way, because there is no referrer to narrow to.

Selecting a row under By engine drills into that one referrer, and the address carries it as ?referrer=, so a drill-down can be linked. This works for every referrer, including the ones only traffic reports, such as Copilot (api/routers/integrations.py#list_ai_traffic). The hero sessions figure, its prior-window delta, and the conversion figures switch to that referrer's own numbers, and the landing-page table narrows to the pages it sent traffic to. The row's own share still tells you how much of the window's traffic that referrer accounts for (frontend/src/routes/(app)/ai-traffic/+page.svelte#sessions). Selecting the same row again, or Show all referrers, returns every figure to the window's total: every referrer's, or the chosen engine's when the engine chip is set. Following a link that names a referrer with no visits in the current view lists every page, with a plain note saying so and a way to clear it, instead of a table that just looks filtered (frontend/src/routes/(app)/ai-traffic/+page.svelte#staleFilter). An old link that named the referrer as ?engine=chatgpt reads as no engine chosen and shows all traffic, because the engine chip takes an engine, not a referrer.

Landing pages are ranked by sessions, each with the engines that sent it traffic and, again only where it drew traffic in the prior window, its own change against that window (api/services/integrations/google/ai_referral_metrics.py#aggregate_pages). The list is capped at the top 50 pages by session count; past that point the page reads "Top 50 pages by sessions" rather than a full count, so a site with more AI-referred landing pages than that sees the leaders, not everything (api/routers/integrations.py#AI_TRAFFIC_PAGE_TOP_N, frontend/src/routes/(app)/ai-traffic/+page.svelte#PAGE_CAP).

Conversions

Whether the screen shows conversion numbers at all is decided once, for the whole window: if total conversions across every engine are zero, the screen shows a prompt to name your conversion events instead of a row of zeros, even narrowed by the engine chip or a referrer to one that happens to have none (frontend/src/routes/(app)/ai-traffic/+page.svelte#hasConversions). That keeps the layout in place as you switch engines rather than jumping every time.

Conversions are not counted at the level you read them. The import asks GA4 for one row per day, page, source, medium, and country, and each of those rows arrives carrying two figures: GA4's own conversion count for it, the property-level metric GA4 already flags as a conversion, and GA4's revenue total for the same row (api/services/integrations/google/ga4_attribution.py#import_ga4_daily_for_project, #_upsert_metrics). A second query then replaces both figures together, row by row, wherever one of your named conversion events fired on it, substituting the count and the value GA4 recorded against your events there; if you have not named any, the same replacement runs using GA4's own purchase and sign_up events instead (api/routers/integrations.py#update_conversion_events, api/services/integrations/google/ga4_attribution.py#_load_project_context, #_fetch_conversion_overrides, #_DEFAULT_CONVERSION_EVENTS). So naming events does not restrict what counts: it overrides GA4's own figures on the rows where your events fired, and GA4's own figures stand everywhere else.

Every conversion figure on the screen is built from sums of those underlying rows: the hero's conversion count, its rate, and the value beside it; each engine's rate and value; and each landing page's count and value (api/services/integrations/google/ga4_attribution.py#_rebuild_ai_referral_attribution, api/services/integrations/google/ai_referral_metrics.py#engine_summary, #aggregate_pages, frontend/src/routes/(app)/ai-traffic/+page.svelte#conversionValue). What you read is therefore a mixture, not one thing or the other: GA4's own count and revenue across every underlying row where none of the counted events fired, and those events' own count and value across the rows where they did. Where the events being counted carry no revenue of their own, a value figure lands below GA4's revenue for the same sessions by whatever the replaced rows would otherwise have contributed.

The prior-window comparison for conversions is built for the window's total, not broken out per engine, so a single engine's row does not carry its own conversion change chip (api/services/integrations/google/ai_referral_metrics.py#engine_summary).

The window, and how the two periods compare

Left alone, AI Traffic opens on the last 28 days. The filter bar's date range chip switches it to 7, 28 or 90 days, carried in the URL as ?days=; any other value in the URL reads as 28, so 90 is the widest window this screen shows (frontend/src/lib/filters.js#readDays).

Every change figure on this screen, the hero sessions number, each engine's row, and each landing page's row, compares the selected window, the days ending yesterday, against the same number of days immediately before it: not a fixed prior period or a year-over-year figure (api/routers/integrations.py#ai_traffic_summary, #list_ai_traffic).

No tile on Overview

Overview has no AI traffic tile. AI referral sessions, conversions and the by-engine breakdown are read here, on this screen (frontend/src/routes/(app)/ai-traffic/+page.server.js#load). The weekly report reads the same summary, over the report's own week and with no engine chosen, when it is built (api/services/integrations/google/ai_traffic.py#summarize_ai_traffic, api/services/weekly_report.py#_assemble_revenue).

Before you see data

AI Traffic needs Google Analytics 4 connected and a GA4 property mapped to this project; either without the other leaves the screen showing a setup prompt instead of a chart (frontend/src/routes/(app)/ai-traffic/+page.server.js#ga4Connected, #propertyMapped). The moment a property is mapped, whether that happens automatically right after you connect or you map one yourself afterward, its one-time 180-day history import is queued immediately rather than waiting for the daily timer, so the pull that populates the full 90-day window this screen allows begins right away (api/routers/integrations.py#map_ga4_property_to_project, #_enqueue_initial_import, #_enqueue_ga4_discovery, api/tasks.py#discover_and_map_ga4_task, api/services/integrations/google/ga4_attribution.py#import_ga4_daily_for_project, #_BACKFILL_WINDOW_DAYS). If that immediate enqueue itself fails, the next daily run backfills any property still missing its history, so a rare miss costs a short delay, not a lost import. After that first pull, the same scheduled import that feeds Traffic → Site traffic also rebuilds this screen's numbers, once a day (#_rebuild_ai_referral_attribution); see Troubleshooting: Search or Site traffic is empty for exactly when that recurring import runs.

Last verified 2026-09-29

Start monitoring your AI visibility.

See how AI search engines talk about your brand.

Free to start. No credit card required.