埋点,是指在应用中添加代码,以收集用户的操作行为和数据,以便后续进行数据分析和产品决策。这些代码通常被称为埋点代码,它们将事件(如点击、滚动、搜索等)和属性(如时间、位置、设备等)捕捉并发送到数据平台。通常情况下,这些数据用于分析用户行为、监控应用程序性能、改进产品功能等方面。
转转 H5 采用的是手动埋点方式,App 内的页面通常需要添加各种埋点,以验证和辅助产品后续决策。今天就和大家聊聊令笔者头疼的埋点,也希望能加深您对埋点的理解~
(相关资料图)
以下部分内容、代码,来源于chatGPT,如有错误,欢迎指出~
埋点内容首先埋点内容一般会包含用户信息、页面信息、事件信息、访问信息等。
用户信息:包括用户的唯一标识(uid)、设备标识(token)、访问设备、浏览器版本以及网络状态等页面信息:包括当前页面的 URL、标题、页面 ID 等信息事件信息:包括用户的行为事件,如点击、滚动、鼠标移动等,以及事件的时间戳、元素路径、事件类型等信息访问信息:包括用户来源、搜索关键词、渠道信息等,计算整个链路的渗透,或者在出现问题时,帮助还原整个用户操作路径,帮助开发者更快的定位、修复问题。埋点方式常见的埋点方式大体可以分为手动埋点、可视化埋点和全埋点三种。
手动埋点在代码中手动加入埋点,相应事件触发的时候,再上报相关埋点。当需要精细化数据或者希望根据业务诉求,定制化添加埋点的时候,就很适合使用这种方式。但缺点就是额外工作量很大,也需要相关的 QA 介入测试,一些复杂的埋点很容易出错,导致延误需求数据分析的时间可视化埋点 需要页面/项目预先接入可视化埋点 SDK,并开启可视化埋点开关,然后相关人员登录可视化圈选后台,选择相应的页面以及圈选需要上报的相关行为埋点,圈选平台和 SDK 进行通信,让 SDK 拿到需要上报的埋点,然后 SDK 自动上报相关的埋点。全埋点是一种将应用程序中所有用户行为都收集和分析的埋点技术,例如打开页面、切入后台、点击某个区域、某个区域曝光等等,优点就是可以更全面、更细致地了解用户行为和需求,缺点就是由于自动记录了各种操作行为的数据,会导致大量的无意义的行为被上报,对服务端的压力比较大,并且也考验从纷繁复杂的埋点中找到所需埋点的能力埋点流程埋点流程大体可以分为埋点触发、上报、校验以及上报到数据平台后的埋点清洗、过滤和分析,进而产出下一步决策。
埋点触发埋点触发大致分为自动触发和手动触发两种方式,上面提及的页面展现通常就是自动触发,当页面打开的时候,就自动上报了。但是像点击埋点就可以用手动触发的,只有当区域被真正点击时,才会进行上报。埋点上报其中埋点上报又分为立即上报和延迟上报两种。立即上报的逻辑相对简单,在埋点事件触发时,就立即上报。但是缺点也很明显,就是上报的埋点量巨大,会给埋点服务造成巨大负担。延迟上报,就是将一段时间内的埋点,收集起来,然后一次性上报。这样无疑就会使上报的次数,急剧减少,减轻了埋点服务压力。但是其中又会涉及埋点上报去重、埋点触发时间校准(如果客户端时间不准怎么办?)等等其他问题,因此相对立即上报来说,延迟上报逻辑上要复杂一些。并且需要数据层面进行过滤、清洗。埋点校验开发者手动添加了部分埋点,需求上线前需要进行验证,确保按照要求进行了上报,其中校验可以使用人工触发,抓包进行校验。也可以通过编写自动化脚本,模拟使用,进行校验。转转侧使用相关的后台,可以通过筛选相关用户、来源以及不同环境,实时接收相关的埋点,进行校验。埋点分析埋点上报之后,数据平台就会拿到相关的埋点数据,对纷繁复杂的数据,进行过滤、清洗,得到产品需要的数据,然后产品就会对数据进行分析,有时可以发现一些问题,以及对后续决策产生影响。埋点常见类型埋点的触发通常与埋点的类型相关,接下来列举几种常见的埋点类型:
页面展现在页面展现时进行上报,H5 环境下一般通过监听onshow或者visibilitychange事件来实现,但是这两者都有一定的兼容性问题。而如果是处于 hybrid 环境,则可以利用宿主环境(客户端)暴露的生命周期来实现,借用原生的生命周期来实现,也更加准确些。页面展现一般用来记录页面的 PV/UV,算是一项非常基础的数据了。点击用户点击某个区域时上报,可以上报相关业务参数,也可以包含点击位置信息,其中位置信息可以用来生成热力图,确定页面的热区,从而可以知道用户对哪部分更加感兴趣,哪部分的转化效率更高,以便调整后续的产品策略。H5 中一般可以通过事件委托来实现,在根结点监听点击事件,当事件冒泡到根结点阶段,触发相应事件。document.addEventListener("click", function(e) { const target = e.target // do something }, true);区域曝光当某个区域出现在视口内,一定时间内进行上报,一般配合点击、下单等数据,观察整个路径的漏斗转化。由于会涉及重复上报的问题,所以一般区域都会有一套规则,生成该区域的唯一标识,防止重复上报。以及在商品列表的场景中存在翻页的情况,就需要再使用MutationObserver监听 DOM 的变化,动态的调用IntersectionObserver进行重复监听。H5 一般有监听页面滚动事件和使用 IntersectionObserver 两种方式来实现
// 1. 监听页面滚动实现const element = document.querySelector(".exposure-ele");window.addEventListener("scroll", () => { const elementPosition = element.getBoundingClientRect(); const windowPosition = { top: 0, left: 0, bottom: window.innerHeight, right: window.innerWidth }; if (isElementInViewport(elementPosition, windowPosition)) { console.log("Element is in viewport!"); } else { console.log("Element is not in viewport!"); }});function isElementInViewport(elementPosition, windowPosition) { return ( elementPosition.bottom > windowPosition.top && elementPosition.top < windowPosition.bottom && elementPosition.right > windowPosition.left && elementPosition.left < windowPosition.right );}// 2. 使用 IntersectionObserver 实现const element = document.querySelector(".exposure-ele");const options = { root: null, rootMargin: "0px", // 设置视口四边延伸的范围,可以利用此做列表数据的提前加载 threshold: 0.5 // 区域与视口相交的阈值};const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { console.log("Element has entered the viewport!"); } else { console.log("Element has left the viewport!"); } });}, options);observer.observe(element);页面停留时长定义用户从进入页面到离开页面的时长,一般需要精确到毫秒级别。停留时间越长,一般代表用户对当前页面越感兴趣,预示产品决策是否可以对此进行一些深耕。热力图通过颜色深浅,标识用户对页面各区域点击的频率。颜色越深,代表点击频率越高,是一种直观、高效发现吸引用户区域的方式。比如常用于商场首页金刚位,可以清晰发现用户对各品类的喜好,就可以动态调整金刚位的类目。一般是通过统计点击埋点上报的位置,进行实现。其中位置又可以分为绝对位置和区域位置两种。绝对位置是指点击时的 x、y 坐标,但是由于各个手机的分辨率不同,点击同一区域的 x、y 坐标也不一样,就需要进行多分辨率的调整、整合,比较复杂。转转现在采用的是后者区域位置,通过页面ID(pageId)、区域ID(sectionId)以及区域次序ID(sortId),对一个区域进行定位,当点击时会上报相关的 pageId、sectionId 以及 sortId,然后就可以统计出页面某个区域、某个次序的点击率,生成相应热力图了。以下是转转游戏账号首页的热力示意图:性能埋点通过记录页面加载过程不同阶段的耗时,帮助开发者发现性能问题,提升页面加载速度,发现可优化的点,提升用户体验。甚至可以与白屏检测相结合,在页面出现问题时,及时报警通知相关人员查看、处理。埋点发送方式
埋点发送即将埋点相关数据发送给数据平台,一般有接口方式、img 标签方式和 sendBeacon 三种方式。
接口方式:通过接口的形式将埋点的信息进行上报,兼容性比较好,但是一些网站可能会禁用脚本,导致失效。创建 img 标签:很多公司都采用 img 标签携带埋点信息进行上报,一方面是图片请求不存在跨域限制(一般而言,埋点发送域名都不是当前域名),另一方面图片标签不需要真正插入到 DOM 节点中,只需要实例化 Image,设置 src 属性就会发出请求,不会阻塞页面渲染,对性能影响较小。const img = new Image()img.src = "https://example.com/log?xxx"
为了追求埋点请求尽可能小,大多采用的是 1*1 像素的透明 GIF 来上报,因为在各种图片格式下,这种相对较小。
sendBeacon 发送该 api 是专门被设计来满足统计和诊断代码的需要,通常需要在页面卸载之前,将相关埋点发出。过早的发送数据可能导致错过收集数据的时机,因此需要等到页面即将卸载时发送数据。在 sendBeacon 出现之前,很难保证在页面卸载之前,可以将数据成功发送,因为用户代理通常会忽略在 unload 事件处理器中产生的异步 XHR。过去为了解决这个问题,开发者们想出了一些 hack 的方法:但是无独有偶,上述方法都存在一个问题,那就是会延迟当前页面的卸载,导致下一个页面出现的更晚。而 sendBeacon 不存在上述问题,它数据发送是可靠的、是异步的,正由于异步发送数据,所以不影响下一导航的载入。一般可以监听 visibilitychange 的 hidden 状态来发送埋点document.addEventListener("visibilitychange", function logData() { if (document.visibilityState === "hidden") { navigator.sendBeacon("/log", analyticsData) }})发起一个同步XMLHttpRequest来发送数据创建一个 img 元素并设置src,大部分用户代理会延迟卸载(unload)文档以加载图像创建一个几秒的 noop 循环总结
以上从埋点内容、方式、流程、常见埋点的类型以及发送方式等方面,介绍了埋点相关的基础概念以及转转采取的方案,希望能对您有所帮助~
参考及引用onshowvisiblechangesendBeaconIntersectionObserverMutationObserver