实时上报停留时长数据:TimeMe.js内置WebSocket通道3步集成教程
实时上报停留时长数据:TimeMe.js内置WebSocket通道3步集成教程
【免费下载链接】TimeMe.jsA JavaScript library to accurately time how long a user views a web page, disregarding idle time and time when the tab or window is minimized.项目地址: https://gitcode.com/gh_mirrors/ti/TimeMe.js
TimeMe.js 是一个专注于「用户页面停留时长统计」的轻量级 JavaScript 库,它能自动剔除用户切走标签页、最小化窗口以及长时间无操作的空闲时间,只统计真实的交互时长。更实用的是,TimeMe.js 内置了 WebSocket 数据上报通道,只需在初始化时传入两个配置项,就能把页面停留时长数据实时推送到你的后端服务器。本文带你用 3 步完成集成,全程不到 10 分钟。
为什么需要"实时"上报停留时长?
传统的停留时长统计通常靠onbeforeunload里的 HTTP 请求上报,但存在两个痛点:
- 数据丢失:页面关闭瞬间发起的异步请求,浏览器往往来不及发完就终止了,统计数据经常漏报;
- 数据失真:用户挂着页面去吃饭、切到别的标签页看视频,这些"假时长"都会污染你的统计口径。
TimeMe.js 的思路是:前端持续监听用户的真实活跃状态(鼠标移动、键盘输入、页面可见性变化等,逻辑见 timeme.js 中的listenForUserLeavesOrReturnsEvents与listForIdleEvents方法),并在与服务器之间始终保持一条 WebSocket 长连接,在用户离开时把时长数据直接推送出去——连接是提前建好的,所以上报成功率高得多。
第 1 步:引入 TimeMe.js 库
二选一即可,新手推荐 npm 方式:
npm install timeme.js --save或者直接克隆源码仓库后引用压缩版文件:
git clone https://gitcode.com/gh_mirrors/ti/TimeMe.js在页面中引入压缩版 timeme.min.js:
<script src="timeme.min.js"></script>如果你不想用构建工具,仓库根目录的 timeme.js 源码可直接引入;想先看效果的话,可以打开 demo/index.html 体验一个实时走时(并自动暂停)的示例页面。
第 2 步:3 行配置启用 WebSocket 通道
TimeMe.js 的 WebSocket 能力是内置的,不需要你手写任何new WebSocket代码。只要在初始化时多传一个websocketOptions配置即可:
TimeMe.initialize({ currentPageName: "my-home-page", // 当前页面名称,用于区分不同页面 idleTimeoutInSeconds: 30, // 30 秒无操作视为空闲,停止计时 websocketOptions: { websocketHost: "ws://your_host:your_port", // 你的 WebSocket 服务地址 appId: "insert-your-made-up-app-id" // 自定义应用标识 } });就这 3 行配置,TimeMe.js 会帮你完成全部底层工作(相关实现见 timeme.js 的setUpWebsocket方法):
| 时机 | TimeMe.js 自动做的事 |
|---|---|
| 页面加载、连接建立 | 立即向服务端发送一条INIT消息,宣告会话开始 |
| 用户活跃/空闲切换 | 自动暂停或恢复计时(不占用的时长不计入) |
| 用户关闭页面 | 在onbeforeunload时发送INSERT_TIME消息,携带本次停留时长 |
第 3 步:后端接收消息并落库
你的 WebSocket 服务端只需要处理两种 JSON 消息:
① 会话开始(INIT)
{ "type": "INIT", "appId": "insert-your-made-up-app-id" }② 时长上报(INSERT_TIME)
{ "type": "INSERT_TIME", "appId": "insert-your-made-up-app-id", "timeOnPageMs": 52340, "pageName": "my-home-page" }其中timeOnPageMs是用户在该页面的有效活跃毫秒数,pageName就是第 2 步里配置的页面名。服务端收到INSERT_TIME后按appId + pageName入库即可。以 Node.js 的 ws 库为例,核心逻辑非常短:
const ws = require("ws"); const server = ws.createServer({ port: 8080 }); server.on("connection", (socket) => { socket.on("message", (raw) => { const msg = JSON.parse(raw); if (msg.type === "INSERT_TIME") { // 把 msg.timeOnPageMs 按 msg.appId / msg.pageName 写入数据库 console.log(msg.pageName, "停留了", msg.timeOnPageMs / 1000, "秒"); } }); });让数据更准确的 3 个实用技巧
- 合理设置空闲阈值:
idleTimeoutInSeconds默认 30 秒,含义是"用户 30 秒没碰鼠标键盘就停表"。分析长文阅读类页面时,建议调大到 60 秒左右; - 单页应用(SPA)记得切换页面名:路由变化时依次调用
TimeMe.stopTimer()→TimeMe.setCurrentPageName("new-page")→TimeMe.startTimer(),各页时长就不会串到一起; - 用聚合接口做自检:
TimeMe.getTimeOnAllPagesInSeconds()可以一次性拿到本次会话所有页面的时长列表,方便你在控制台里和后端收到的数据对账。
关于空闲检测与离开/返回回调的完整行为,可参考 tests/tests.js 中的单元测试用例;全部 API 的中文说明见 README.md 的 "API" 章节。
常见问题
Q:不开 WebSocket 行不行?
行。TimeMe.js 本身不强制要求,你也可以在任意事件点调用TimeMe.getTimeOnCurrentPageInSeconds()拿到时长后,自行用 HTTP 上报。但如前文所说,onbeforeunload里的异步 HTTP 请求在部分浏览器中可能发不出去,数据完整性不如内置的 WebSocket 通道。
Q:appId 是做什么用的?
它只是一个你自定义的字符串标识,用于区分不同应用或不同站点的上报数据,TimeMe.js 本身不做校验,服务端按它做数据隔离即可。
总结
| 步骤 | 你做了什么 | 耗时 |
|---|---|---|
| ① 引入 timeme.min.js | npm 安装或克隆仓库 | ~1 分钟 |
② 配置websocketOptions | 3 行初始化代码 | ~2 分钟 |
③ 后端解析INSERT_TIME消息 | 一条 JSON 入库 | ~5 分钟 |
至此,你就拥有了一个"剔除空闲时间 + 实时可靠上报"的停留时长统计方案——对新手来说,这正是把 TimeMe.js 用在生产环境里最快的一条路径 🚀
【免费下载链接】TimeMe.jsA JavaScript library to accurately time how long a user views a web page, disregarding idle time and time when the tab or window is minimized.项目地址: https://gitcode.com/gh_mirrors/ti/TimeMe.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
