为 Astro 站点添加隐私优先分析
Astro 的 View Transitions 会悄无声息地破坏标准分析脚本。这里是无需 cookie 或同意横幅即可追踪每次路由变化的正确方式。
Astro 的 View Transitions 会就地替换页面内容,无需浏览器完整重新加载——这意味着任何依赖 DOMContentLoaded 或 load 的分析脚本只会在首次访问时触发一次。后续每次客户端导航都是隐形的。这不是你的配置错误;这是 ClientRouter 工作方式的根本性后果。
同样的隐形追踪问题也存在于 SvelteKit 2 和 Remix 中,但每个框架的修复方法不同。在 Astro 中,答案是 astro:page-load 生命周期事件。
为什么常规的 script 标签会失败
当 <ClientRouter /> 启用时(在 Astro 4 中通过 astro:transitions 选择启用,在 Astro 5 中默认启用),导航不会卸载页面。Astro 在后台获取下一页,替换 DOM,并更新 URL——所有这些都不会销毁当前的 JavaScript 上下文。
通过普通 <script> 标签加载的追踪器脚本会被 Astro 的构建流水线视为打包的模块脚本。打包的模块脚本在每个页面会话中只执行一次。追踪器初始化,为登陆页面触发一次 pageview,然后在用户导航时不再运行。
要在每次导航时触发,初始化逻辑必须接入 Astro 的导航生命周期。正确的钩子是 astro:page-load,它在新页面可见且所有阻塞脚本加载完成之后触发——既在首次加载时也在每次后续转换时触发。
正确的集成方式
在你的根布局中(src/layouts/Layout.astro 或等效文件)添加一次追踪器脚本,然后附加一个 astro:page-load 监听器:
---
// Layout.astro
---
<html lang="en">
<head>
<!-- your head content -->
</head>
<body>
<slot />
<script
is:inline
src="https://api.monoid.website/tracker.min.js"
data-site-id="YOUR_SITE_ID"
async
></script>
</body>
</html>
is:inline 指令告诉 Astro 的打包器原样保留此脚本。否则 Astro 会将该脚本作为模块处理、去重,并抑制重新执行。使用 is:inline 后,script 标签会原封不动地输出到每个页面的 HTML 中。
对于不使用 View Transitions 的站点,这就是你所需要的全部。追踪器在加载时触发一次,搞定。
处理 View Transitions 导航
如果你的站点使用 <ClientRouter />,追踪器内置的 history.pushState 钩子会在每次转换后正确触发——追踪器在内部监听 Astro 的导航事件。无需额外配置。
要验证,请打开 DevTools 网络选项卡并按 collect 筛选。在两个页面之间导航。你应该会看到每次导航有一个 POST 请求,包括首次加载。
如果你是有条件地注入追踪器并需要在每次切换后重新初始化(例如,在动态岛挂载之后),你可以手动触发重新运行:
<script data-astro-rerun>
// This block re-executes after every View Transition.
// Use sparingly — most tracker logic should not live here.
if (window.__monoid) {
window.__monoid.trackPageview();
}
</script>
data-astro-rerun 属性强制内联脚本在每次转换后重新执行。请注意,它隐含 is:inline,因此只适用于非打包脚本。
区分环境
Astro 项目通常有本地开发、预览和生产环境。使用环境变量来保存 site_id 并在开发中抑制追踪:
---
const siteId = import.meta.env.PUBLIC_MONOID_SITE_ID
---
{siteId && (
<script
is:inline
src="https://api.monoid.website/tracker.min.js"
data-site-id={siteId}
async
></script>
)}
在 .env 中为生产环境设置 PUBLIC_MONOID_SITE_ID,本地不设置。Astro 将带有 PUBLIC_ 前缀的变量暴露给客户端;仅服务器端的变量(无前缀)在浏览器执行的代码中不可见。
你不需要的东西
无需 cookie 同意横幅。无需 CMP 集成。收集端点从 IP 地址、User-Agent、服务器端密钥和当前日期计算每日访客哈希:
visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)
哈希每 24 小时重置一次。访客的设备上不存储任何内容。粗略的浏览器系列和设备类型在服务器端从请求 User-Agent 推导得出,用于聚合报告——完整的 User-Agent 字符串、浏览器版本和持久标识符从不存储。
Astro 站点通常是完全静态的或边缘渲染的,JavaScript 极少。添加一个不到 2 KB、无 cookie、无同意要求的分析脚本,自然契合这种理念。无需维护 npm 包,无需更新 SDK,也无需为分析处理记录 GDPR 法律依据。