返回博客

为 SvelteKit 应用添加隐私优先分析

SvelteKit 2 与其他框架的客户端导航拦截方式不同。这里是无需 cookie 或同意横幅即可追踪路由变化的正确方式。

SvelteKit 2 悄然破坏了大多数现有的分析集成。在 SvelteKit 1 中运行良好的普通 <script> 标签,在 SvelteKit 2 中只会在硬刷新时触发,错过所有客户端导航。标准的修复方式——挂钩 history.pushState——也不起作用,因为 SvelteKit 在 pushState 被调用之前就在路由器层级拦截了导航。Monoid 追踪器开箱即用地正确处理了这一点。

为何常规方法会失败

传统的分析脚本通过对 history.pushStatehistory.replaceState 进行猴子补丁来检测路由变化。SvelteKit 的路由器调用其自己内部的导航原语,仅在路由转换已经开始之后作为副作用调用 pushState。当被补丁的 pushState 触发时,新路由可能尚未完全渲染,而在某些导航类型(程序化 goto() 调用、带预加载的 <a> 点击)中,时序产生重复或遗漏的事件。

这是广泛报道的 Google Analytics GA4 在 SvelteKit 2 应用中仅记录首次加载 pageview 问题的根本原因。

正确的方法

通过 <svelte:head> 将 Monoid 追踪器脚本一次性添加到你的根 +layout.svelte

<svelte:head>
  <script
    async
    src="https://api.monoid.website/tracker.min.js"
    data-site-id="YOUR_SITE_ID"
  ></script>
</svelte:head>

追踪器内置的 DOMContentLoaded 监听器在初始页面加载时触发。对于后续的客户端导航,追踪器的 history.pushState 钩子在 SvelteKit 的内部导航解决之后触发——意味着每个路由(包括第一个)都被精确追踪一次,没有重复或遗漏的事件。

要验证,请在 DevTools 中打开网络选项卡并观察到 /collect 的 POST 请求。每次路由变化应该看到一次。

区分暂存流量

SvelteKit 项目通常在开发期间运行于 localhost。注册一个单独的站点并将其 site_id 绑定到环境变量,确保开发流量永不污染生产指标:

<script>
  const siteId = import.meta.env.VITE_MONOID_SITE_ID
</script>

<svelte:head>
  {#if siteId}
    <script
      async
      src="https://api.monoid.website/tracker.min.js"
      data-site-id={siteId}
    ></script>
  {/if}
</svelte:head>

.env.local 中为开发设置 VITE_MONOID_SITE_ID(或保持未设置以抑制追踪),并在部署环境中为生产设置。{#if siteId} 块确保在变量未设置时追踪器永不注入。

你不需要的东西

无需 cookie 同意横幅。无需更新 cookie 政策。无需检查 navigator.cookieEnabled。收集端点从 IP 地址、User-Agent、服务器端密钥和当前日期派生每日访客哈希:

visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)

哈希每 24 小时重置一次,且无法被反向还原为 IP 或 User-Agent。访客的设备上不存储任何内容。这意味着该集成不触发 ePrivacy 或 PECR 同意要求——没有什么需要同意。

在仪表板中验证

部署后,打开你的分析仪表板并在你的实时站点上的多个路由间导航。每次导航应该产生一个具有正确路径的新 pageview 条目。如果无论导航如何都只看到一个条目,请检查脚本是否在根布局中加载,以及 VITE_MONOID_SITE_ID 是否在生产环境中设置。

你使用的 SvelteKit 适配器(Cloudflare、Vercel、Node、静态)不会影响分析收集,因为追踪完全在水合后于浏览器中进行。