接入指南Install guide

把一段代码贴进网站 <head>,几秒后控制台就能看到访客——包括他们是从豆包、DeepSeek、通义千问还是 ChatGPT 过来的。这页讲清楚贴什么、为什么这么设计、怎么埋转化、以及数据没出来时怎么查。 Paste one snippet into your site's <head> and visitors show up in the console within seconds — including which AI engine referred them (Doubao, DeepSeek, Qwen, ChatGPT and more). This page covers what to paste, why it is built this way, how to track conversions, and what to check when data does not appear.

三步接入Three steps

  1. 拿贴码——登录 控制台 → 「站点管理」,复制你站点那一行下方的代码。每个站点的 Tag ID 不同,别混用。还没有账号?当前为邀请制内测,先去提交申请,审核通过会把激活链接发到你留的邮箱 —— 申请时务必留邮箱,它同时是登录名。 Get the snippet — sign in to the console, open Sites, and copy the code under your site. Each site has its own Tag ID; do not reuse one across sites.No account yet? GEO Tag is in invite-only beta — request access first and we'll email you an activation link once approved.
  2. 贴进 <head>——越靠前越好,这样访客一进页面就开始计时。一次性工作,之后我们更新采集逻辑你不用再动。 Paste it into <head> — as early as possible, so engagement timing starts the moment the page opens. This is a one-off; you never need to touch it again when we ship updates.
  3. 验证——打开你的网站,再回控制台看「实时」页,几秒内应出现 1 个活跃访客。没出现就看本页最后一节。 Verify — open your own site, then check Realtime in the console. One active visitor should appear within seconds. If not, see the last section.

网站是 Vue / React / Next.js 这类单页应用也一样贴,路由切换会自动算作新的页面浏览,不需要额外配置。 Single-page apps (Vue / React / Next.js) work the same way — route changes are counted as page views automatically, with no extra configuration.

贴码长什么样What the snippet looks like

VG-XXXXXXXX 换成你自己的 Tag ID(控制台里直接复制的已经替换好了): Replace VG-XXXXXXXX with your own Tag ID (the copy in the console already has it filled in):

<script>(function(w,d,s,id){
  w.geotag=w.geotag||function(){(w.geotag.q=w.geotag.q||[]).push(arguments)};
  w.geotag('config',id);
  var js=d.createElement(s);js.async=1;
  js.src='https://cdn.jsdelivr.net/npm/@geo-analytics/tag@1/dist/vtag.js?id='+id;
  js.onerror=function(){var f=d.createElement(s);f.async=1;
    f.src='https://geo-analytics.info/vtag.js?id='+id;d.head.appendChild(f)};
  d.head.appendChild(js)
})(window,document,'script','VG-XXXXXXXX');</script>

为什么有两个地址Why there are two URLs

默认从 CDN(jsDelivr)加载,全球边缘节点就近分发。onerror 那一行是保险:万一 CDN 在你的访客网络下不可达,会自动换成我们自己的服务器加载,不会因为 CDN 抖动就丢一整段数据。这行只在加载失败时触发,正常情况下不会重复加载。 The script loads from a CDN (jsDelivr) by default, served from the nearest edge node. The onerror line is the safety net: if the CDN is unreachable on your visitors' network, loading falls back to our own server automatically, so a CDN hiccup does not silently cost you a chunk of data. It only fires on load failure — nothing is loaded twice in normal operation.

无论脚本从哪个地址加载,数据都上报到同一个地方——上报地址是编译进脚本里的固定值,不随加载来源变化。 Wherever the script is loaded from, data is reported to the same place — the collector endpoint is a constant compiled into the script and does not depend on the loading origin.

其它引用方式Other ways to reference it

只用我们的服务器,不走第三方 CDN——公司安全策略不允许引入外部 CDN 时用这个: First-party only, no third-party CDN — use this if your security policy forbids external CDNs:

<script async src="https://geo-analytics.info/vtag.js?id=VG-XXXXXXXX"></script>

锁定版本 + 完整性校验——需要审计"这个文件永远不会变"时用。注意锁版后你不会自动收到修复,升级要手动改;而且 SRI 与浮动版本 @1 互斥,哈希必须对应那个确切版本。 Pinned version with Subresource Integrity — for audits that require the file to be immutable. Note that pinning means you no longer receive fixes automatically, and SRI is incompatible with the floating @1 tag: the hash must match that exact version.

<script async
  src="https://cdn.jsdelivr.net/npm/@geo-analytics/tag@1.0.0/dist/vtag.js?id=VG-XXXXXXXX"
  integrity="sha384-…" crossorigin="anonymous"></script>

已经装了旧版本的站点Sites already running an older snippet

早期贴码用的全局函数名是 VigilathTag它继续有效,不需要动——新版脚本把这个名字保留为永久别名,你页面上已有的 VigilathTag('event', …) 调用照常记录。想换成新贴码也可以,两者不会冲突。 Earlier snippets used the global name VigilathTag. It still works and needs no change — the current script keeps that name as a permanent alias, so existing VigilathTag('event', …) calls on your pages keep recording. You may switch to the new snippet at any time; the two do not conflict.

自动采集了什么What is collected automatically

贴上就有,不用写一行代码: These require no code beyond the snippet:

事件Event 什么时候触发When it fires
first_visit访客第一次到访A visitor's first ever visit
session_start每段会话开始At the start of each session
page_view每次页面浏览,含单页应用的路由切换Every page view, including SPA route changes
scroll页面滚动到 90%Page scrolled to 90%
click点击跳出本站的外链A click on an outbound link
user_engagement页面处于可见状态的累计时长(换页或离开时结算)Accumulated visible time, settled on navigation or unload

来源归因Source attribution

这是 GEO Tag 与普通统计工具的区别:很多 AI 引擎跳转时不带 referrer,普通工具只能把这些访客算成「直接访问」。我们额外识别引擎在链接上注入的参数指纹——比如通义千问会给出站链接拼 spm=5176.* 且完全不传 referrer,靠这个指纹仍能归因到它。 This is where GEO Tag differs from conventional analytics: several AI engines strip the referrer on outbound links, so ordinary tools bucket those visits as "Direct". We additionally recognise the parameters those engines inject — Qwen, for example, appends spm=5176.* and sends no referrer at all, and that fingerprint is enough to attribute it.

归因记两份:首次来源(这个访客最初是从哪来的,终身保留)和本次会话来源(这一段访问是从哪来的)。两者互不覆盖——同一个人上周从豆包来、今天从 DeepSeek 来,不会被算成一次。 Attribution is recorded twice: first touch (where this visitor originally came from, kept for their lifetime) and session source (where this particular visit came from). Neither overwrites the other — someone who arrived via Doubao last week and via DeepSeek today is not collapsed into one.

新会话在以下任一情况开始:30 分钟无操作、跨自然日、utm_source 变化,或入口引擎变化。最后一条很关键——不然同一个人 30 分钟内先后从豆包和千问进来,后一次的来源会被前一次盖掉。 A new session starts on any of: 30 minutes of inactivity, a day boundary, a change of utm_source, or a change of entry engine. That last one matters — otherwise a Qwen visit arriving inside a still-live Doubao session would lose its source entirely.

可选:把「直接访问」和「来源被抹」分开(加一行 Nginx)Optional: separate "Direct" from "source erased" (one Nginx line)

有些引擎连参数指纹也没有。实测 DeepSeek 网页版给出站链接加了 rel="noreferrer",referrer 被完全抹掉、也不注入任何参数——这种访客和「有人直接输网址」在数据里长得一模一样,谁也分不出来。 Some engines leave no parameter fingerprint either. Measured: DeepSeek on the web puts rel="noreferrer" on its outbound links, so the referrer is gone entirely and no parameter is added — such a visit is indistinguishable from someone typing your address by hand.

浏览器还会发一个 Sec-Fetch-Site 请求头,它属于 Fetch Metadata,不受 Referrer-Policy 影响,引擎抹不掉。JS 读不到请求头,但你的服务器可以把它回传给页面。在你的站点配置里加一行: Browsers also send a Sec-Fetch-Site request header. It is Fetch Metadata and is independent of Referrer-Policy — an engine cannot suppress it. JavaScript cannot read request headers, but your server can echo it back to the page. Add one line to your site config:

add_header Server-Timing 'sfs;desc="$http_sec_fetch_site"' always;

加完之后,原本笼统的「来源未知」会拆成两档:外部来源(来源被抹)——确实从别的站点跳来,只是对方抹掉了身份;直接访问——地址栏或书签。不加也完全不影响其它功能,只是这一档拆不开。 With that in place, the single "Source unknown" bucket splits in two: External (source erased) — the visit really did come from another site that hid its identity; and Direct — a typed URL or bookmark. Skipping this changes nothing else; you simply keep the combined bucket.

要点:「外部来源」不等于「AI 带来的」。任何抹掉来源的入口都会落进去——App 内嵌浏览器、带 rel="noreferrer" 的普通链接都算。它给的是 AI 归因的上界,不是 AI 流量本身。我们宁可这么标,也不愿把它算成「直接访问」让你以为 AI 没带来人。 Important: "External" is not the same as "brought by AI". Any entry point that hides its origin lands there — in-app browsers, ordinary rel="noreferrer" links. It is an upper bound on AI referrals, not AI traffic itself. We would rather label it this way than count it as "Direct" and let you conclude AI sent you nobody.

埋转化事件Tracking conversions

自动采集不知道你的「成功」是什么。在关键动作上加一行,报表里就能看到哪个 AI 引擎真正带来了转化,而不只是带来了流量: Automatic collection cannot know what "success" means on your site. Add one line at the key action and the reports will show which AI engine actually drives conversions, not just traffic:

<button onclick="geotag('event','conversion',{conversion_name:'signup',value:199,currency:'CNY'})">
  免费试用Start free trial
</button>

也可以在自己的 JS 里调用,比如表单提交成功后: You can also call it from your own JavaScript, for example after a form submits successfully:

geotag('event', 'conversion', { conversion_name: 'contact_form' });
geotag('event', 'sign_up',    { plan: 'pro' });          // 自定义事件名也可以// custom event names work too

事件名和参数名建议用小写加下划线,并且全站统一——报表按名称聚合,signUpsign_up 会被算成两个不同的事件。 Use lower_snake_case for event and parameter names, and keep them consistent across the site — reports aggregate by name, so signUp and sign_up count as two different events.

验证与排查Verify & troubleshoot

确认装好了Confirm it is installed

打开你的网站,按 F12 打开浏览器开发者工具: Open your site and press F12 to open the browser developer tools:

实时页没数据Nothing shows in Realtime

可能原因Likely cause 怎么确认How to check
域名不在白名单Domain not in the allowlist 上报请求返回非 204。控制台「站点管理」确认你的域名已登记——写主域即可覆盖所有子域 The collect request returns something other than 204. Check that your domain is registered under Sites — the apex domain covers all subdomains
Tag ID 贴错或贴串了Wrong or mismatched Tag ID Network 里 vtag.js?id= 后面的值,要和控制台里这个站点的 Tag ID 一致 The value after vtag.js?id= in the Network tab must match this site's Tag ID in the console
广告拦截插件挡住了An ad blocker is blocking it 用无痕窗口或关掉拦截插件再试。若确实被拦,改用只走我们服务器的写法 Retry in a private window or with the blocker disabled. If it is genuinely blocked, switch to the first-party-only snippet
贴码没进 <head>Snippet not in <head> 查看页面源代码搜 geotag;有些 CMS 会过滤掉 <script>,需要用它自带的「自定义代码」入口 View source and search for geotag; some CMSes strip <script> and require their own "custom code" field
CSP 拦截Blocked by CSP 源代码里有贴码、Network 里却看不到 vtag.js 的请求 —— 多半是站点的内容安全策略挡下了。见下一节 The snippet is in the source but vtag.js never appears in the Network tab — most likely your Content Security Policy. See the next section

内容安全策略(CSP)拦截Content Security Policy (CSP)

如果你的服务器下发了 Content-Security-Policy 响应头,而其中没有放行本产品的域名,浏览器会在脚本加载前就把它拦掉。这种失败很难自己发现:页面一切正常、贴码明明在源代码里、也不报任何用户可见的错误,只是数据一条都不进来。 If your server sends a Content-Security-Policy header that does not allow our domains, the browser blocks the script before it ever loads. This failure is hard to spot on your own: the page works fine, the snippet is right there in the source, and nothing user-visible breaks — you simply get no data at all.

怎么确认:按 F12 打开控制台(Console),如果看到类似下面这行,就是它: How to confirm: press F12 and open the Console. A line like this means CSP is the cause:

Loading the script 'https://cdn.jsdelivr.net/npm/@geo-analytics/tag@1/dist/vtag.js'
violates the following Content Security Policy directive: "script-src 'self'"

需要放行两处,少一处都收不到数据: Two directives must be updated — missing either one still yields no data:

指令Directive 要加什么What to add 为什么Why
script-src https://cdn.jsdelivr.net
https://geo-analytics.info
允许加载采集脚本。两个来源都要加 —— 贴码默认走 CDN,失败时回落自托管,只放行一个的话另一条路仍会被拦 Allows the script to load. Add both — the snippet uses the CDN by default and falls back to first-party hosting, so allowing only one still blocks the other path
connect-src https://geo-analytics.info 允许把数据发回来。只放行 script-src 是不够的 —— 脚本能跑起来,但上报会被 connect-src 拦掉,结果还是零数据 Allows the data to be sent. script-src alone is not enough — the script would run but reporting would be blocked by connect-src, still leaving you with no data

改完大致长这样(其余指令保持你原来的设置,不需要放松): The result looks roughly like this — keep your other directives as they were, nothing needs loosening:

Content-Security-Policy:
  default-src 'self';
  script-src  'self' 'unsafe-inline' https://cdn.jsdelivr.net https://geo-analytics.info;
  connect-src 'self' https://geo-analytics.info;
  style-src   'self' 'unsafe-inline';
  img-src     'self' data:;
  font-src    'self';
  base-uri    'self';
  frame-ancestors 'none';

只想放行一个域名?把贴码改成只用自托管那一行(见前文「其它引用方式」),然后 script-srcconnect-src 都只加 https://geo-analytics.info 即可。代价是失去 CDN 边缘加速 —— 对访客主要在国内的站点,这个代价很小。 Prefer to allow just one domain? Switch to the first-party-only snippet (see "Other ways to reference it" above), then add only https://geo-analytics.info to both script-src and connect-src. You lose CDN edge acceleration — a minor cost if your visitors are mostly in one region.

CSP 通常配在 Nginx / Apache 的响应头或应用框架的中间件里,不在页面 HTML 中。改完记得清缓存重试 —— 响应头常被 CDN 或反向代理缓存。 CSP is normally set in your Nginx/Apache response headers or a framework middleware, not in the page HTML. After changing it, clear caches and retry — response headers are often cached by a CDN or reverse proxy.

数据对不上Numbers look off

还是不对?把你的站点地址和遇到的现象发给我们,我们可以从服务端直接查这个 Tag ID 有没有收到数据。 Still not right? Send us your site address and what you are seeing — we can check server-side whether any data has arrived for your Tag ID.