跟踪的事件
页面浏览量说明打开了哪个页面,但并不能说明读者是否复制了代码片段、向助手提问、滚过介绍内容,或离开前往你的注册页面。本页完整列出了还会记录的其他内容,按字段逐一说明,这样你就能在创建目标或漏斗之前确认想要衡量的事项是否已经被记录。
你将获得什么#
三十六个命名的 docs.* 事件,分为七个类别,每个文档站点都会记录这些事件,无需配置,也无需标签管理器。其中的每一项都是 Feeds 中可以筛选的一行数据,可以与目标进行匹配,可以在分析概览中排名,也可以通过 MCP 按访客读取。
记录这些事件不会消耗项目余额,并且无论使用何种方案,列表内容都不会改变。
目录#
每个事件都携带您项目的完整名称(owner/repo)。还携带列表示它在此基础上额外添加的内容。标记为信标的事件会在读者离开时由 navigator.sendBeacon 发送;其余事件则通过普通日志传输发送,该传输会批量处理两秒钟。
AI 助手#
| 事件 | 触发时机 | 还携带 |
|---|---|---|
docs.ai_open |
读者打开助手面板时 | conversation_id |
docs.ai_query |
提交问题时 | question, answer, conversation_id, turn |
docs.ai_like / docs.ai_dislike |
对答案进行点赞或点踩时 | path, conversation_id, question |
docs.ai_copy |
复制答案时 | conversation_id |
docs.ai_navigate |
点击答案引用的链接时 | query, path, conversation_id, source(badge 或 sources)— 信标 |
docs.ai_outbound |
答案中的链接将读者带离您的网站时 | href, host, conversation_id, question — 信标 |
docs.ai_conversation |
每次对话一次,在首次成功的答案被命名时 | topic, intent, competitor, question, answer_completeness, gap_type |
docs.ask_ai_outline |
从页面大纲中按下“询问 AI”时 | — |
docs.ai_navigate 和 docs.ai_outbound 特意设计为两个事件,而不是一个。
第一个表示读者足够信任该答案,因而打开了它引用的页面;
第二个表示助手将他们交给了您的应用、您的代码仓库,或完全不同的其他地方——这是一个商业问题,而不是理解问题。
搜索#
| 事件 | 触发时机 | 还携带 |
|---|---|---|
docs.search_open |
打开页面内搜索框时 | — |
docs.search_navigate |
点击搜索结果时 | query、path |
docs.search_no_result |
查询无结果时 | query |
阅读与互动#
| 事件 | 触发时机 | 还携带 |
|---|---|---|
docs.pageview |
页面被提供时 | path、lang、trafficType、referrer、userAgent、source,以及边缘节点解析出的国家/地区/城市/坐标 |
docs.read_time |
读者离开页面时 | path、seconds — 信标 |
docs.heading_view |
标题滚动进入视口时 | path、heading(作为 #anchor)— 信标 |
docs.scroll_to_top |
使用返回顶部控件时 | — |
docs.widget_toggle |
内容小组件打开或关闭时 | widget、enabled |
docs.theme_toggle |
切换浅色/深色模式时 | theme |
docs.language_switch |
使用语言选择器时 | from、to |
docs.pageview 是浏览器不会发送的唯一事件。它在服务器端写入,因此即使读者禁用了 JavaScript,它也会存在 — 这也是为什么完全由页面浏览组成的访问会被视为爬虫。在从缓存提供的页面上,页面浏览则由浏览器通过信标发送,摄取端点会填充相同的 IP 和地理位置信息,因此两条路径会生成相同的记录。
seconds 以原始形式发出,并在任何报告对其求和之前截断为最多 300 秒。有关此截断及其存在原因,请参阅阅读时长。
内容操作#
| 事件 | 触发时机 | 还携带 |
|---|---|---|
docs.copy_code |
复制代码块时 | — |
docs.copy_page |
复制整个页面时 | — |
docs.copy_markdown |
将页面复制为 Markdown 时 | — |
docs.copy_dropdown |
使用复制菜单时 | action |
docs.edit_on_github |
点击“在 GitHub 上编辑”时 | path |
导航#
| 事件 | 触发时机 | 还携带 |
|---|---|---|
docs.sidebar_nav |
侧边栏条目被点击时 | path |
docs.heading_nav |
页面内大纲中的条目被点击时 | heading、path |
docs.page_nav |
使用上一页/下一页时 | direction(prev 或 next)、path |
docs.internal_link |
指向您的其他页面的页面内链接被点击时 | href |
docs.heading_nav 和 docs.heading_view 特意共用 #anchor 格式,因此无论读者是跳转到某个章节还是滚动到该章节,该章节聚合的数据都相同。
离站与来源#
| 事件 | 触发时机 | 同时携带 |
|---|---|---|
docs.outbound_link |
链接离开您的文档 | href、host、path — 信标 |
docs.header_link |
您网站页眉中的链接被点击 | label、href |
docs.utm |
带有营销活动标签的访问到达 | 按原样提供的 utm_* 参数 |
docs.page_exit |
读者离开网站或重新加载页面 | path — 信标 |
docs.claim_banner_seen |
发布/认领横幅显示 | claim_token |
docs.claim_click |
发布/认领横幅被点击 | claim_token — 信标 |
docs.page_exit 仅在真正离站或重新加载时触发。站内导航不会产生该事件,这正是一次访问的最后一个 docs.page_exit 所对应的页面是读者实际离开页面的原因。
反馈#
| 事件 | 触发时机 | 还携带 |
|---|---|---|
docs.page_feedback_up |
页面被投票为有帮助 | path、国家/地区 |
docs.page_feedback_down |
页面被投票为没有帮助 | path、国家/地区 |
方向体现在事件的名称中,而不是某个 vote 字段中:事件存储的架构是一组固定的字段名,无法识别的字段会被直接拒绝,而不是被丢弃。投票通过服务器路由记录,因此 webhook 可以在投票时触发;如果该请求失败,浏览器会直接记录相同的事件,因此计数仍会保留。
自动触发,或取决于某项功能#
Docsbook 中没有任何用于跟踪的开关,任何事件也没有 enabled 标志。上面列出的每个事件,都会在产生它的功能存在时触发,因此列表分为两类:
| 始终存在 | 仅在使用该功能后存在 |
|---|---|
| 页面浏览、阅读时长、标题查看、退出、复制、内部链接和外部链接、侧边栏导航和上一页/下一页导航、搜索、主题、返回顶部 | 每个 docs.ai_* 事件(需要面向读者的助手,这是一项付费功能——请参阅定价),docs.language_switch(需要第二种语言),docs.edit_on_github(需要关联的代码库),docs.utm(需要你自行标记的链接),docs.widget_toggle(需要页面上有一个小组件),反馈事件对(需要投票小组件),两个 docs.claim_* 事件(仅在未认领的网站上触发) |
因此,报告中的“空”事件有两种可能的解读,而且两者并不相同:没有人执行过该操作,或者目前还没有任何功能能够执行该操作。
如何交付#
普通事件会通过一种批处理两秒后再通过
fetch 发送的传输机制。这对于点击后页面仍保持打开的情况没有问题,但对于点击后页面不会保持打开的情况则会丢失所有内容——因此,与离开页面相关的事件会采用另一条路径:
- 组件会注册一个退出收集器。在
pagehide上,每个收集器中的内容都会被汇总到一个信标中,最多包含 100 个事件,并发送到同源端点。 - 在 iOS 上,
visibilitychange → hidden会触发相同的刷新,因为pagehide在那里并不可靠。 - 收集器只返回尚未发送的内容,因此 iOS 刷新后紧接着真正退出不会导致重复计数,并且从前进/后退缓存中恢复的页面还可以再次执行刷新。
标题视图通过一个阈值为 0、具有 -15% 底部边距的 IntersectionObserver 进行收集,并且每个标题一旦被看到就会取消观察:每次页面浏览中一个标题只计数一次,并且只有在其越过视口底部后才计数,而不是刚刚探入视口的瞬间。
为什么这是正确的做法#
| 规则 | 为什么它在运行它的浏览器上有效 | 来源 |
|---|---|---|
退出时事件通过 beacon 发送,绝不用防抖的 fetch |
Beacon 请求“保证会在页面卸载前启动,并且无需阻塞请求即可运行完成” | W3C Beacon API |
| 不要为了发出事件而阻塞退出过程 | Beacon 规范针对的替代方案——“通过同步 XMLHttpRequest 发出阻塞请求,插入无操作忙循环”——“会阻止用户代理执行时间关键型操作……并损害用户体验” | W3C Beacon API |
监听 pagehide,并额外监听可见性变化 |
unload“仍然不可靠,因此除非绝对必要,否则应避免使用”;pagehide“会在 unload 事件触发的所有情况下触发”,并且还会在进入前进/后退缓存时触发 |
web.dev:bfcache |
使用 IntersectionObserver 检测标题是否进入视口,而不是使用滚动处理程序 |
通过 DOM 查询计算位置“已知会导致(昂贵的)样式重新计算和布局”,而网站“滥用滚动处理程序”会导致“滚动卡顿”;异步传递“消除了执行昂贵 DOM 和样式查询、持续轮询的需要” | W3C Intersection Observer |
使用 rootMargin,在标题越过折叠线后再计数 |
rootMargin应用“偏移量……实际上扩大或缩小用于计算交集的框”——这是表达“确实已到达”而非“技术上发生了重叠”的诚实方式 |
W3C Intersection Observer |
| 页面隐藏后仍继续计数,测量到的是错误的对象 | 之所以存在 Page Visibility API,是因为“Web 开发者一直按照页面始终可见的情况来设计网页” | W3C Page Visibility Level 2 |
如何读取一位访客的事件#
两个 MCP 工具可以端到端地重建一位匿名访客的路径,而且两者都是
读取工具:get_top_visitors列出某个时间段内最活跃的访客,
get_visitor_activity按顺序返回一位访客的事件。
get_top_visitors(period: "7d", limit: 25)
→ [{ visitor_id: "a1b2…", pageview_count: 14, first_seen, last_seen, country }, …]
get_visitor_activity(visitor_id: "a1b2…", period: "7d")
→ { first_seen, last_seen, country, language, pageview_count,
events: [
{ event: "docs.pageview", at, path: "guides/quick-start" },
{ event: "docs.page_feedback_down", at, path: "guides/quick-start" },
{ event: "docs.search_no_result", at, query: "rotate api key" },
… ] }visitor_id是读取者 IP 的加盐哈希值,作用域限定为您的项目;不会返回原始
IP。请参阅测量工作原理。
限制与未决问题#
- 任何 webhook 都无法针对
docs.*事件触发。 这些事件存在于事件 仓库中,没有任何机制会分发它们。它们可以在 Feeds 中被筛选并 保存到列表中,在那里它们显示为not_sent,因为它们本来就是 如此。针对读者行为的告警通过派生的 webhook 事件实现——流量下降、热门搜索、无结果搜索——而不是通过此目录实现。请参阅 webhooks。 - 事件按事件计数,而不是按访问计数。 一位读者复制五个
代码片段,就会产生五行
docs.copy_code。任何需要按访问计数的内容——跳出、转化、 目标——都需要通过重建访问来派生,而不是对这个列表求和。 - 禁用 JavaScript 的读者只会贡献
docs.pageview。 上述其他每个 事件都需要运行中的脚本,而这正是行为爬虫过滤器所依赖的。 question和answer字段会携带读者输入的任何内容。 原始事件 读取会经过一个编辑器处理,它会屏蔽键或值看起来像令牌、密钥、JWT 或授权标头的任何字段, 但如果读者在你的助手中输入了个人信息,那么这些信息就已经被输入到你的事件存储中。 保留期限为 30 天。- 未决问题:该目录具有权威性,但并不涵盖整个流。 可以验证的是,这 36 个名称是每个界面——面板、Feeds、目标验证、MCP——都从同一个共享列表中读取的名称,因此目标只能声明在其中的名称上。无法确定的是:还有少量
额外的
docs.*名称由未认领网站的预告流程发出,且不在该列表中,这意味着它们会到达存储中,却不会显示在 UI 中。请将这 36 个名称视为你可以操作的完整事件集合,而不要将其视为流中每个字符串的完整清单。