你发了一条产品演示视频,后台只告诉你“67%的人看完了”。这个数字回答不了核心疑问:大家是在第15秒的客套话里流失的,还是在第3分钟的操作演示处反复回拖?完成率只讲“看了多少”,热力图才能标出“看了哪里”——那些被集体跳过的开头、被反复观看的段落、以及观众突然离开的断崖点。

目前,这类每秒钟观看热度的图表,往往是视频托管平台的高级分析功能。但原理并不玄乎,核心就是一条规则:别盯着播放事件,改为追踪播放时间里的“区间段”。因为快进、重看会让事件说谎,但一段段覆盖到的媒体时间不会。你只需准备一个客户端间隔追踪器、一个信标接收端和一段画布渲染代码,不用引入任何分析厂商,数据也留在自己手里。

打开网易新闻 查看精彩图片

我们动手写一个追踪器,不到80行,零外部依赖。一次观看会话被表达为若干区间:{start, end},时间轴用的是媒体自身的时间。播放推进时打开一个区间,一旦发生暂停、跳转、播放结束或标签页隐藏,就关闭区间。有人倒退重看,只会形成重叠的新区间,这正是热力图需要的信号——同一个位置被多次覆盖,说明观众在那段纠结或琢磨。

具体实现上,我们监听timeupdate事件来驱动tick,但做了一个防御:如果在两次tick之间,时间位置后退或往前跳跃超过5秒,就认为错过了一次跳转,主动关闭当前区间并以新位置重新开始。这样能适应timeupdate在不同设备上4赫兹到66赫兹的触发频率差异。关闭区间时,我们过滤掉长度小于0.5秒的杂讯,只保留有价值的观看片段。当页面隐藏或关闭,立即触发flush,以JSON格式打包videoId、sessionId和spans数组,通过navigator.sendBeacon发送到指定的收集端点。

sendBeacon是这套机制能存活的关键。它不会因为标签页关闭而被浏览器取消,相当于一个“发射后不管”的请求,保证数据最终到达。即便用户看完视频直接关窗,追踪到的区间也会完整送出。与任何video元素对接都很简单,不论是原生的标签,还是hls.js、video.js驱动的播放器,只需在实例化WatchTracker时传入视频元素、videoId和收集地址。

热力图的构建逻辑也随之清晰:收集到的所有区间,在服务端按每秒一个计数器展开聚合,最终用Canvas绘制出来。你立刻就能看见,哪一秒是黄金停留点,哪一秒是观众拍拍屁股走人的悬崖。这个自己搭建的工具,也许不会比商业平台精细,但它解答问题时,你手里握着全部原始数据,而且知道每一行代码为什么这样写。