[🛠] 整理博客统计仪表板的混乱
✨ GPT-5.5 的摘要
修正公开统计页面中访问和浏览量混在一起显示的问题,将基于30分钟会话的访问数与基于页面打开次数的浏览量分开,并整理成移动端也易读的仪表板记录。
做完公开博客统计页面之后,我马上发现了一个不舒服的地方。
数字确实出来了。
但数字的名称太容易混在一起。
访客、访问、浏览量、会话、page view。在博客界面上它们看起来很像,但在实际统计模型里并不是同一个东西。公开计数器如果把这些概念说得模糊,即使数字能正常显示,也很难让人信任。
一开始我以为“今日浏览量”“本月浏览量”“总浏览量”这样简单显示就够了。但侧边栏真正想展示的,更接近今天博客有多少次访问,而不是文章被打开了多少次。

所以我重新拆分了结构。
访问
-> 30分钟无活动后结束的会话
浏览量
-> 页面或文章被打开的次数

4943不是访问数
首先需要修正的是baseline的含义。
从Google Analytics拿来的4943这样的值是screenPageViews。也就是页面浏览量。如果把它显示成总访客数或总访问数,那就是错误的数字。
所以我同时整理了Worker和文档。
totalPageViews
-> GA screenPageViews baseline + D1 page views
totalSessions
-> GA sessions baseline + D1 sessions
访问和浏览量不能放在同一个baseline上。于是我新增了单独seed会话baseline的route。
/admin/seed-session-baseline
GitHub Actions的Worker部署流程里也加入了会话baseline seed步骤。如果Worker代码部署了,但baseline为空,公开页面上的总访问数就会看起来不正常。
直接使用/track响应
最初的结构有点绕。
客户端先用/track增加计数,再重新读取/analytics填充画面。这样因为缓存和请求顺序,刚刚反映的访问可能不会马上出现在屏幕上。读者看到时会像是“我刚打开页面,为什么今日访问没变?”
所以现在/track响应会一起返回最新的analytics payload。
流程变成这样。
页面加载
-> POST /track
-> Worker反映会话/浏览量
-> 同一个响应包含最新analytics
-> 客户端用该payload渲染侧边栏和当前页面浏览量
之后的周期性刷新仍然读取/analytics。
也就是说,首屏优先使用刚刚更新过的payload。之后再用读取API跟随最新状态。
会话不能随着每次页面移动增加
浏览量可以随着读者移动到不同文章而增加。
但访问不同。同一个人在同一个博客会话里读了三篇文章,不应该变成三次访问。所以我在Worker里加入sessions表,用visitor hash和最后活动时间连接会话。
标准是30分钟。
最后活动后30分钟以内
-> 同一会话
超过30分钟
-> 新会话
这样侧边栏的今日/本月/总访问数会比page view更稳定。相反,文章级浏览量仍然按page path增加。
多语言页面也遵循同一原则。
/daily-review/.../和/en/daily-review/.../是同一篇文章的不同语言版本。浏览量key使用canonical path,同一会话内切换语言不会再增加访问数。
把仪表板改得更像表格
最初的统计页面以KPI卡片和条形列表为中心。
这并不差。但当访问和浏览量同时出现时,结构开始变得含糊。卡片变多后,移动端页面变长,也很难一眼看出哪个数字是某个期间的访问,哪个是浏览量。
所以我把上方比较区域改得更接近表格。

期间 访问 浏览量
选择期间 n n
今日 n n
本月 n n
总计 n n
总计也拆成两行。
总计
-> 2026/06/09之后的直接统计
总计
-> 包含2026/06/09之前的统计
这两个含义不同。
直接统计是从公开维度开始进入D1之后的值。包含以前统计的总计,则是加上GA baseline后的公开总数。把它们混在一行里,数字会显得更大,但无法和详细维度对应。
所以仪表板说明也拆开了。
访问:排除30分钟内重复访问。浏览量:页面打开次数。
直接统计从2026/06/09开始。
让直接日期输入更好用
统计页面经常要改日期。
一开始我以为range=today、range=month、range=total、range=custom按钮就够了。但要查看直接期间,就得一直改开始日和结束日。
所以我把输入做得更像一个小工具。
YYYY/MM/DD显示
隐藏的date picker
年/月/日segment选择
用ArrowUp / ArrowDown调整日期
用鼠标wheel调整日期
开始日和结束日范围clamp
外观仍然只是两个小输入框,但调整日期不那么烦了。
我也放弃了只有点击custom时才显示日期输入的方式。日期输入始终可见,点击preset按钮时日期会移动到对应范围。
这样更可预期。
详细维度分成标签页
详细维度全部展开会很乱。
页面、访客环境、来源、地区/语言都有用,但全部摆在一个屏幕上很难读。所以我把它们分成标签页。
页面
访客环境
来源
地区/语言
页面path可能很长,所以label加入title,并调整样式避免换行和省略破坏布局。以/开头的page dimension值会变成链接。
目标不是做一个华丽的dashboard。
我只是想在手机上打开时,也能快速看到哪些文章被读、今天访问数是多少、浏览量大概多少。
多语言标签也一起对齐
统计页面不只有韩语。
还有/en/analytics/、/ja/analytics/、/zh-Hans/analytics/等active locale页面。所以“访问”“浏览量”“30分钟会话”“GA浏览量 + D1”这样的标签,也要同步到各locale的front matter。
如果漏掉这一点,结构虽然改了,其他语言页面里还会留下旧文案。
在多语言博客里,修改一个功能并不是只改一个页面。同一界面存在于多个locale里,标签含义也必须一起移动。
确认过的内容
主要确认了渲染和数字含义。
node --check cloudflare/ga-stats-worker.js
node --check assets/js/custom/analytics-dashboard.js
node --check assets/js/custom/visitor-stats.js
bundle exec jekyll build
Cloudflare Worker deploy
GitHub Pages deploy
确认标准如下。
侧边栏是否把sessions显示为访问
文章级浏览量是否继续使用page view
总访问和总浏览量是否使用不同baseline
直接统计总计和包含GA的总计是否分开
直接期间输入是否不与today/month/total preset冲突
移动端期间/访问/浏览量表格是否不横向溢出
这次工作之后,统计页面反而安静了一些。
数字更多了,但更不容易混淆。访问就是访问,浏览量就是浏览量。总计也是总计,但直接统计总计和包含历史的总计不是一个东西。
重点不是让数字看起来更大。
而是不隐藏每个数字的含义。
留下评论