☰
GoatCounter 前端接入指南:count.js 脚本的设置、数据参数与 API 方法全解析
2026/10/10 8:56:56 网站建设 项目流程
  • 数据分析
  • 后端

【免费下载链接】goatcounter

Easy web analytics. No tracking of personal data.

项目地址:https://gitcode.com/gh_mirrors/go/goatcounter
点击查看免费下载

GoatCounter 是一款强调隐私保护的轻量级网页统计工具("Easy web analytics. No tracking of personal data."),而其官方推荐的主流接入方式就是本文要讲解的count.js前端脚本。本文以 tpl/help/js.md 为骨架,结合 public/count.js 与 public/count.v5.js 的源码实现、handlers/count.go 的后端接收逻辑,系统讲解如何在你的站点中引入count.js、通过data-goatcounter-settings属性与window.goatcounter对象配置统计行为、定制上报数据,并掌握count()、url()、filter()、bind_events()、get_query()等核心方法。读完后,你可以在自己的网站上完成从基础埋点到事件跟踪、自定义路径、本地测试的完整接入方案。

为什么优先使用 count.js

将 GoatCounter 添加到网站的主要方式就是使用count.js脚本,这也是迄今为止最简单的集成方式。脚本默认托管在http://gc.zgo.at/count.js(正式部署时通常使用 https),你也可以自行托管,或将脚本内容直接内联进页面——相关说明见 tpl/help/countjs-host.md。此外还有带子资源完整性(SRI)校验的稳定版本可供选择,见 tpl/help/countjs-versions.md。

一个值得注意的设计决策是:该脚本按设计以未压缩(unminified)形式下发,便于任何人轻松审查其行为。脚本本身不大(约 3.2KB),压缩后也只能省下约 1KB,收益有限,因此选择了透明可读。这一点与项目"隐私透明、代码可审计"的理念一致。

脚本加载后会向window.goatcounter暴露一系列设置项与方法。从服务端角度看,脚本最终会把数据以查询参数的形式发送到/count端点,由 handlers/count.go 中的backend.count处理器接收并写入内存存储(goatcounter.Memstore.Append(hit)),随后在后台任务中落库。

设置(Settings):两种配置方式与全部支持项

配置count.js最直接的方式是给<script>标签加上data-goatcounter-settings属性,也可以直接在window.goatcounter上赋值。两种方式效果一致,下面分别演示。

方式一:data-goatcounter-settings 属性

例如,允许来自本机/内网的请求(用于本地联调测试集成):

<script>var s = document.querySelector('script[data-goatcounter]') if (s && s.dataset.goatcounterSettings) { try { var set = JSON.parse(s.dataset.goatcounterSettings) } catch (err) { console.error('invalid JSON in><script> // 这段必须放在 count.js 加载 *之前*;否则页面浏览可能已发出, // 而且这里的赋值会直接覆盖脚本建立的对象。 window.goatcounter = {allow_local: true} </script> <script>设置说明no_onload页面加载时不执行任何操作(不自动上报),适用于你想手动调用count()的场景;同时也不会绑定任何事件。no_events不自动绑定事件(点击跟踪)。allow_local允许来自本地地址(localhost、192.168.0.0等)的请求,用于在本地测试集成。allow_frame允许页面处于 frame/iframe 中时上报。endpoint自定义上报页面浏览的端点(会覆盖data-goatcounter里的 URL)。仅在设置了no_onload时有用。

关于endpoint的补充说明:对照源码 public/count.js,端点的解析优先级是document.querySelector('script[data-goatcounter]').dataset.goatcounter优先,找不到data-goatcounter属性时才回退到goatcounter.endpoint。也就是说data-goatcounter属性永远优先于 JS 中设置的endpoint——如果你在 JS 里定制 endpoint,就不要在 script 标签上写data-goatcounter。动态按主机名切换端点的完整示例见 tpl/help/modify.md。

数据参数(Data Parameters):定制上报内容

你可以自定义发送给 GoatCounter 的数据。有一个关键规则需要牢记:默认值仅在值为null或undefined时生效,空字符串""、数字0或其他任何值都不会触发默认值(对照源码中的is_empty判断:v === null || v === undefined || typeof(v) === 'function',见 public/count.js)。

数据参数还支持回调函数:默认值会作为参数传入回调,回调的返回值才会真正发送到服务端。特别地,如果path的回调返回null,则完全不会发送任何页面浏览。

变量说明
path页面路径(不含域名)或事件名称。默认取<link rel="canonical">的值(若存在),否则取location.pathname + location.search。
title人类可读的标题。默认是document.title。
referrer访客来源;可以是 URL(如https://example.com)或任意字符串(如June Newsletter)。默认使用Referer请求头。
event将path视为事件而非 URL。布尔值。
no_session本次页面浏览不跟踪会话,这样即使刷新页面也始终计数。主要用于事件跟踪(如统计每一次按钮点击)。一般不建议用于普通页面浏览。

示例:总是上报 /hello

<script><script> window.goatcounter = {path: '/hello'} </script> <script>var data = { p: (vars.path === undefined ? goatcounter.path : vars.path), // path r: (vars.referrer === undefined ? goatcounter.referrer : vars.referrer), // referrer t: (vars.title === undefined ? goatcounter.title : vars.title), // title e: !!(vars.event || goatcounter.event), // 是否为事件 s: window.screen.width, // 屏幕宽度 b: is_bot(), // 疑似 bot 的标识 q: location.search, // 原始查询串 }

处理流程是:先取出 path/referrer/title 的值(若是函数则暂存为回调),再对空值(null/undefined/函数)套用默认值(document.referrer、document.title、get_path()),最后依次执行回调。no_session在 vars 中单独处理,为真时追加ns参数。默认path的取法get_path()(public/count.js)会优先检查同域(允许www子域差异)的<link rel="canonical">,否则回退到当前location.pathname + location.search。这与 tpl/help/path.md 中关于 canonical URL 与自定义 path 的说明相互印证。

更多高级示例

在发送前修改数据的更多高级用法(如去掉首页跟踪、去掉.html后缀、按主机名动态切换端点)见 tpl/help/modify.md;控制发送路径的专项文档见 tpl/help/path.md。

方法(Methods):手动控制上报与过滤

count.js以async方式加载,因此默认情况下你的脚本运行时它可能尚未加载完毕。要安全地使用下面的方法,要么去掉async,要么用一个简单的轮询回调:

var t = setInterval(function() { if (!window.goatcounter || !window.goatcounter.count) return clearInterval(t) // 在这里安全地使用 goatcounter。 }, 100)

count(vars)

发送一个页面浏览或事件到 GoatCounter。vars参数即上文数据参数一节描述的对象,会被合并进全局的window.goatcounter(若其存在)。

对照 public/count.js,count()的实际执行链路为:

  1. 先调用goatcounter.filter(),若返回过滤原因则console.warn('goatcounter: not counting because of: ' + f)并放弃;
  2. 调用goatcounter.url(vars)生成上报 URL,若path回调返回了null则提示后放弃;
  3. 优先使用navigator.sendBeacon(url)发送(页面卸载时更可靠);若sendBeacon不存在或返回false(例如被 CSP 内容安全策略拦截),则回退为在页面底部插入一张1px透明 GIF 图片请求:img.src = url,并把alt=""、aria-hidden="true"以保证可访问性与布局影响最小(源码见 public/count.js)。

url(vars)

生成将要发送给服务器的 URL,vars参数行为与count()一致。由 public/count.js 可知:它会调用get_data()组装参数,并在查询串中追加一个 5 位随机字符串rnd(源码注释解释:浏览器不总是遵守 Cache-Control,加随机数是为了绕过缓存);若找不到端点则warn('no endpoint found')。

注意:使用url()时你可能仍希望调用filter()来排除预渲染(prerender)请求及其他各类情况,避免把不该计数的请求算进去。

filter()

判断本次请求是否应被过滤,返回一个说明原因的字符串,无需过滤时返回false。

对照 public/count.js 的完整过滤逻辑,它按顺序检查:

  • document.visibilityState === 'prerender'→ 返回'visibilityState'(预渲染不计);
  • 页面处于 frame/iframe 且未设置allow_frame→ 返回'frame';
  • 主机名匹配本地地址(localhost、127.、10.、172.(16-31).、192.168.、0.0.0.0)且未设置allow_local→ 返回'localhost';
  • file:协议且未设置allow_local→ 返回'localfile';
  • localStorage中被标记了skipgc === 't'(通过#toggle-goatcounter开关)→ 返回'disabled with #toggle-goatcounter';
  • 以上均不命中 → 返回false。

示例用法:

var f = goatcounter.filter() if (f) { if (console && 'log' in console) console.warn('goatcounter: not counting because of: ' + f) return }

补充:脚本里还内置了一个"跳过自己的访问"的便捷开关——当location.hash === '#toggle-goatcounter'时切换localStorage中的skipgc标记(见 public/count.js)。

bind_events()

为所有带data-goatcounter-click属性的元素绑定点击事件。页面加载时会自动调用,除非设置了no_onload或no_events。如果你在页面加载后动态插入元素,需要手动调用它。

对照 public/count.js,绑定逻辑是:遍历所有*[data-goatcounter-click]元素,跳过已标记goatcounterBound的,同时绑定click和auxclick(中键点击),并把事件名、标题、referrer 一起上报。点击事件的完整用法(包括data-goatcounter-click、data-goatcounter-title、data-goatcounter-referrer、data-goatcounter-no-session等属性)见 tpl/help/events.md。

get_query(name)

从当前页面 URL 获取单个查询参数,不存在时返回undefined。常用于从 URL 中提取referrer,例如:

<script> window.goatcounter = { referrer: function() { return goatcounter.get_query('ref') || goatcounter.get_query('utm_campaign') || goatcounter.get_query('utm_source') || document.referrer }, } </script> <script><script><script> window.goatcounter = {endpoint: '{{.SiteURL}}/count'} // [.. count.js 的内容 ..] </script>

自托管不会收到新功能或更新,但/count端点保证长期兼容,因此脚本永远不会失效。

小结

count.js的设计处处体现"简单 + 可审计 + 隐私友好":脚本未压缩以便审查;通过data-goatcounter-settings或window.goatcounter提供统一配置入口;filter()从源头过滤掉预渲染、iframe、本地地址等噪声;get_data()对空值、回调、canonical 路径做了细致的默认值处理;上报时优先sendBeacon、失败回退 1px 图片请求。配合 tpl/help/events.md 的事件跟踪、tpl/help/modify.md 的数据改写示例和 tpl/help/countjs-versions.md 的版本策略,你可以按需组合出从"一行埋点"到"精细事件统计"的完整接入方案。如需深入后端行为,可以继续阅读接收上报的 handlers/count.go(含 bot 检测、IP 忽略列表、Collect选项下的地理位置与语言解析等逻辑)。

  • 数据分析
  • 后端

【免费下载链接】goatcounter

Easy web analytics. No tracking of personal data.

项目地址:https://gitcode.com/gh_mirrors/go/goatcounter
点击查看免费下载

相关推荐

上一篇:如何用雀魂牌谱屋快速提升麻将水平:从战绩查询到安定段位的完整数据分析指南
下一篇:香山 XiangShan 处理器贡献指南:Bug 报告、提交规范与 PR 自动化标签全解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询