跳到正文
DEV Community· Furqan Khalid·· 2 小時前AI 評分65

ChatGPT、Perplexity 和 Claude 引薦流量追蹤指南:GA4 正則表達式、伺服器日誌與「暗 AI」問題

Tracking ChatGPT, Perplexity and Claude Referrals Properly: GA4 Regex, Server Logs and the 'Dark AI' Problem

AI 導讀

文章提供追蹤 ChatGPT、Perplexity、Claude 等 AI 助手引薦流量的方法,涵蓋 GA4 自訂頻道、伺服器端記錄與 SQL 報表。

正文

"How much traffic do we get from ChatGPT?" sounds like a one-line question. In practice, the honest answer is "at least X, and probably more."

AI assistants do send visitors: people click the citations in ChatGPT search, Perplexity, Claude, Gemini and Copilot. But that traffic reaches you in at least four different shapes, and default analytics setups only catch some of them.

This post gives you:

  1. A classifier that recognises AI referrals from the referrer and UTM tags
  2. A GA4 custom channel group regex
  3. Express/Next.js middleware to log AI visits server-side
  4. SQL to report on them, plus a way to estimate the part you can't see

The four shapes of AI traffic

Shape What you see Example
Referrer present document.referrer / Referer header from an AI domain https://www.perplexity.ai/
UTM tagged AI product adds a UTM to outbound links ?utm_source=chatgpt.com
No referrer Desktop apps, mobile apps, copy-pasted links, strict referrer policies Lands as Direct
Inside Google Clicks from AI Overviews / AI Mode Lands as Organic Search (google)

Shapes 1 and 2 are trackable. Shape 3 is the "dark AI" traffic. Shape 4 is AI-driven, but Google reports it as part of normal Search (Search Console's generative AI performance report, rolled out to all sites in 2026, is the place to look for that).

![Four shapes of AI traffic: referrer present, UTM tagged, no referrer and inside Google, with how trackable each one is]

Image: diagram by the author.

1. A classifier you can reuse everywhere

Keep the rules in one module so the browser, the server and your SQL all agree.

// ai-referrers.js
export const AI_SOURCES = [
  { name: "ChatGPT",    hosts: ["chatgpt.com", "chat.openai.com"],          utm: ["chatgpt.com", "chatgpt"] },
  { name: "Perplexity", hosts: ["perplexity.ai", "www.perplexity.ai"],     utm: ["perplexity", "perplexity.ai"] },
  { name: "Claude",     hosts: ["claude.ai"],                              utm: ["claude.ai", "claude"] },
  { name: "Gemini",     hosts: ["gemini.google.com", "bard.google.com"],   utm: ["gemini", "gemini.google.com"] },
  { name: "Copilot",    hosts: ["copilot.microsoft.com", "copilot.cloud.microsoft"], utm: ["copilot"] },
  { name: "DeepSeek",   hosts: ["chat.deepseek.com"],                      utm: ["deepseek"] },
  { name: "Meta AI",    hosts: ["meta.ai", "www.meta.ai"],                 utm: ["meta.ai"] },
  { name: "Grok",       hosts: ["grok.com"],                               utm: ["grok"] },
];

export function classifyAI({ referrer = "", url = "" }) {
  let refHost = "";
  try { refHost = new URL(referrer).hostname.toLowerCase(); } catch {}

  let utmSource = "";
  try { utmSource = (new URL(url).searchParams.get("utm_source") || "").toLowerCase(); } catch {}

  for (const src of AI_SOURCES) {
    if (src.hosts.some(h => refHost === h || refHost.endsWith("." + h))) {
      return { source: src.name, method: "referrer" };
    }
    if (src.utm.includes(utmSource)) {
      return { source: src.name, method: "utm" };
    }
  }
  return null;
}
classifyAI({ referrer: "https://www.perplexity.ai/", url: "https://example.com/docs" });
// → { source: "Perplexity", method: "referrer" }

classifyAI({ referrer: "", url: "https://example.com/pricing?utm_source=chatgpt.com" });
// → { source: "ChatGPT", method: "utm" }

Domains change. Gemini used to be Bard, Copilot has moved hosts more than once, and new assistants keep launching. Review this list every quarter and treat it as config, not code.

2. GA4: a custom channel group

Some 2026 reports say GA4 added a built-in AI assistant channel. I couldn't find a Google document listing exactly which sources it covers, so I still recommend your own channel group, where you control the rules.

Admin → Data display → Channel groups → Create new channel group → Add new channel named AI Assistants, with the condition:

  • Session source · matches regex ·
^(.*\.)?(chatgpt\.com|chat\.openai\.com|perplexity\.ai|claude\.ai|gemini\.google\.com|bard\.google\.com|copilot\.microsoft\.com|copilot\.cloud\.microsoft|chat\.deepseek\.com|meta\.ai|grok\.com)$|^(chatgpt|perplexity|claude|gemini|copilot|deepseek|grok)$

Two settings people get wrong:

  1. Don't add a medium = referral condition. UTM-tagged ChatGPT visits often arrive as chatgpt.com / (none) or (not set). Restricting the medium drops them.
  2. Move the channel above "Referral" and "Organic Search". GA4 evaluates channels top to bottom and the first match wins.

Channel groups apply to historical data in reports, which is handy for checking how this year compares with last.

3. Log AI visits server-side

GA4 misses visitors who block analytics, and you can't easily join it with your own data (signups, orders). A tiny middleware fixes both.

Express

// ai-log.js
import { classifyAI } from "./ai-referrers.js";

export function aiReferralLogger(db) {
  return (req, res, next) => {
    if (req.method !== "GET" || !req.accepts("html")) return next();

    const hit = classifyAI({
      referrer: req.get("referer") || "",
      url: `${req.protocol}://${req.get("host")}${req.originalUrl}`,
    });

    if (hit) {
      db.query(
        `INSERT INTO ai_visits (ts, source, method, path, user_agent)
         VALUES (now(), $1, $2, $3, $4)`,
        [hit.source, hit.method, req.path, req.get("user-agent") || ""]
      ).catch(() => {}); // never block the request on analytics
    }
    next();
  };
}

Next.js (App Router)

Middleware can't easily write to a database at the edge, so forward the hit to a route handler or your log pipeline:

// middleware.ts
import { NextResponse, type NextRequest } from "next/server";
import { classifyAI } from "./lib/ai-referrers";

export function middleware(req: NextRequest) {
  const hit = classifyAI({ referrer: req.headers.get("referer") ?? "", url: req.url });
  if (hit) {
    // Structured log line; ship it with your log drain.
    console.log(JSON.stringify({ type: "ai_visit", ...hit, path: req.nextUrl.pathname, ts: Date.now() }));
  }
  return NextResponse.next();
}

export const config = { matcher: ["/((?!_next|api|.*\\..*).*)"] };

Note the referrer only shows the origin (https://chatgpt.com/), not the conversation, and that's how it should be. You'll never know which prompt sent the visit, so don't try to fingerprint it.

4. Report on it

-- Weekly AI visits by source
SELECT date_trunc('week', ts) AS week, source, count(*) AS visits
FROM ai_visits
GROUP BY 1, 2
ORDER BY 1 DESC, 3 DESC;

-- Which pages do AI assistants send people to?
SELECT path, source, count(*) AS visits
FROM ai_visits
WHERE ts > now() - interval '30 days'
GROUP BY 1, 2
ORDER BY 3 DESC
LIMIT 25;

The second query is the useful one. AI assistants tend to send people to a different set of pages from Google: deep docs pages, comparison pages and pricing are common. That tells you which content is getting cited.

5. Estimating the dark part

You can't classify visits with no referrer, but you can spot when Direct traffic behaves like AI traffic:

  • Deep-page Direct landings. Real "direct" visits (typed URL, bookmark) mostly land on the homepage. A spike in Direct visits to /docs/configuring-webhooks usually means someone shared or cited the link, and AI apps are a common source.
  • Correlate with known AI visits. If a page's referrer-tagged ChatGPT visits double and its deep-page Direct visits rise in the same week, some of that Direct is probably AI too.
  • Ask. A "How did you hear about us?" field on signup with an "AI assistant (ChatGPT, Claude…)" option is low-tech and surprisingly informative.
-- Deep-page "direct" sessions: a rough proxy for unattributed shares/citations
SELECT landing_path, count(*) AS sessions
FROM sessions
WHERE channel = 'Direct'
  AND landing_path NOT IN ('/', '/login', '/app')
  AND ts > now() - interval '30 days'
GROUP BY 1
ORDER BY 2 DESC
LIMIT 25;

Report AI traffic as "tracked AI visits (floor)" and leave it at that. Inventing a multiplier for the dark part won't survive the first question in a meeting.

Traffic is the lagging indicator

Referral tracking tells you what happened after an assistant cited you. It doesn't tell you how often you were mentioned without a click, or how often a competitor was recommended instead. Those are the leading indicators. We track them in Vista AI's brand visibility dashboard, which samples real prompts across the major assistants. Whatever you use, put both views next to each other: visibility going up while referrals stay flat usually means you're being mentioned but not linked.


Did I miss an AI source that sends you traffic? Post the referrer host in the comments and I'll add it to the list.

Next in the series: ChatGPT can't cite what Bing hasn't indexed: IndexNow in Next.js.

來源:DEV Community · dev.to