前端埋点统计方案思考

埋点即监控用户在应用表现层的行为,于产品迭代而言至关重要。埋点数据分析是产品需求的 来源,检验功能是否达预期的 佐证。前端较服务端更接近用户,本小白将在此对前端埋点统计方案述说一二。

采集埋点数据可做如下分析(以百度统计为例):

用户属性用户行为 转化各类可视化图表:

不同产品对数据的关注角度不同,可按需采集。如信息流产品对停留时长的关注度更高(统计页面访问 & 跳出时间),商城类较注重“复购率”(统计新老用户),广告类更追求最大限度。

埋点统计通常分两类:

  • 页面访问量统计

  • 功能点击量统计


页面访问量统计

页面访问量统计通常分两类:

  • PV:页面访问人次

  • UV:页面访问人数

页面访问量,并非仅仅取决于其内容吸引力,影响因素包含入口 外观位置深度 等等(在此不考虑刚需)。入口外观属 UI 设计范畴,入口位置可通过分析用户点击热力图调整,入口深度可通过分析用户访问路径调整。

用户点击 热力图 形如:

将核心页面入口置于热力图红色区域?

采集页面加载 fromto 以获知用户访问路径:

分析可知用户普遍 访问深度、每一深度 & 每一页面的 流失率 等,依照结果调整核心页面入口源、入口深度?

页面访问量,也并非仅仅取决于产品设计。假若 PV 稳定的页面访问量 爆跌,便需考虑其加载成功率了(或许是枚技术 bug)。


前端如何实现全局 PV 统计,以 Vue 应用为例。

方案一

通过在入口文件 index.js 全局定义 Router.beforeEach

import App from './app'
import Router from './router'

Router.beforeEach((to, from, next) => {
    App.logEvent({
        type: 'visit',
        name: to.name,
        time: new Date().valueOf(),
        params: {
            from: {
                name: from.name,
                path: from.path,
                query: from.query
            },
            to: {
                name: to.name,
                path: to.path,
                query: to.query
            }
        }
    })
    next()
})

停留时长可通过 (跳转页 time - 当前页 time) 获知,但关闭应用时如何统计?监听应用关闭 onbeforeunload + onunload

其中 App.logEvent 为自定义 Vue 插件 App 中的 method,用于向服务器发起 埋点上报请求

import Request from './utils/request'

const App = {
    // ...
    logEvent (opts) {
        Request({
            url: '/log/event',
            method: 'POST',
            data: {
                type: opts.type,
                name: opts.name,
                time: opts.time,
                params: opts.params || {}
            }
        })
    }
}
App.install = (Vue, options) => {
    Vue.prototype.$app = {
        // ...
        logEvent: App.logEvent
    }
}

export default App
方案二

通过在入口文件 index.js 全局注册混入 beforeRouteEnterbeforeRouteLeave 对象:

import Vue from 'vue'

Vue.mixin({
    beforeRouteEnter (to, from, next) {
        next(vm => {
            vm.$app.logEvent({
                type: 'visit',
                name: to.name,
                time: new Date().valueOf(),
                params: {
                    from: {
                        name: from.name,
                        path: from.path,
                        query: from.query
                    },
                    to: {
                        name: to.name,
                        path: to.path,
                        query: to.query
                    }
                }
            })
        })
    },
    beforeRouteLeave (to, from, next) {
        this.$app.logEvent({
            type: 'visit',
            name: to.name,
            time: new Date().valueOf(),
            params: {
                from: {
                    name: from.name,
                    path: from.path,
                    query: from.query
                },
                to: {
                    name: to.name,
                    path: to.path,
                    query: to.query
                }
            }
        })
        next()
    }
})

关闭应用时 beforeRouteLeave 是否触发?

上述方案存在明显缺陷:

  • 官方曰慎用全局混入对象!!!

  • 对于页面同名钩子函数 beforeRouteEnterbeforeRouteLeave,如何 merge?如何 next

  • 含子路由的页面将调用 2beforeRouteEnterbeforeRouteLeave,PV 无形翻倍...

我猜此刻有打全局混入 createddestroyed 并通过 this.$route 获知访问对象主意的人了,试试看?

令人不知所措的输出,打印次数与 路由表 长度一致嗷~

其中 this.$app.logEvent(vm.$app.logEvent) 等同方案一中 App.logEvent,不再赘述。


如何恰当选取全局 PV 统计方案?

  • SPA 应用:仅单入口,在入口文件全局定义 Router.beforeEach 方便可行。

  • MPA 应用:多入口,在每个入口文件定义 Router.beforeEach?可封装公用逻辑(伪装单入口),免去重复构造 entry 的成本。

  • SPA + MPA 混合应用:emmmmmm...采用 MPA 应用的统计方案。

  • SSR 应用:为追求更好的 SEO 而采用服务端渲染(SSR)。以 Jinja(Python 模板)为例,调用 TemplateView 则为渲染页面(不同于前后端分离项目,服务端无法获知接口调用与页面渲染的对应关系),统计其调用次数及 TemplateName 可知页面 PV。

至于 UV,统计 PV 时采集 userId 去重即可。若应用无用户管理体系,采集 IPdeviceId 也可粗略得知 UV(不精准)。


功能点击量统计

不同功能的点击量不同,同一功能不同区域的点击量也不同:

按钮点击量,影响因素包含按钮 外观位置入口 等等(在此不考虑刚需)。按钮外观属 UI 设计范畴,按钮位置可通过分析用户点击热力图调整,按钮入口可通过分析触发源分布调整。

举一实例:

运营同学会将一张图片裁切成 n 个区域,点击每一区域所推荐商品不同。统计区域点击坐标,据热力图调整商品排序以求 利益最大化


前端如何实现功能点击量统计?

本人将功能点击分两类:

  • 带业务接口请求

  • 无业务接口请求

方案一

将埋点上报混入业务接口请求,无接口请求的点击采用自定义上报:

其中 param keys 指代需上报的业务请求参数 key list(并非全部参数均需随埋点上报)。

上述方案大大节约请求数,但存在明显缺陷:

  • 将埋点上报混入业务接口,上报 crash 不仅丢失统计数据,还将影响主功能。

  • 统计与业务 高耦合,两者尽量不混于同一服务。

方案二

将所有点击事件视为同一类,走统一上报接口:

logEvent (opts) {
    Request({
        url: '/log/event',
        method: 'POST',
        data: {
            type: opts.type,
            name: opts.name,
            time: opts.time,
            params: opts.params || {}
        }
    })
}

上述方案也存在明显缺陷:

  • 请求量翻倍:但统计与业务服务拆分后,请求并非同一组服务器承担。

  • 待上报的点击事件函数均需调用 logEvent:封装一枚附带埋点上报的 组件,以 Vue 为例。

<template>
    <div class="vc-trace" @click="triggerClick">
        <slot></slot>
    </div>
</template>

<script>
import Request from './utils/request'

export default {
    name: 'Trace',
    props: {
        type: {
            type: String,
            default: ''
        },
        name: {
            type: String,
            default: ''
        },
        from: {
            type: String,
            default: ''
        },
        params: {
            type: Object,
            default: () => ({})
        }
    },
    methods: {
        triggerClick () {
            Request({
                url: 'XXX/log/event',
                method: 'POST',
                data: {
                    type: this.type,
                    name: this.name,
                    from: this.from,
                    time: new Date().valueOf(),
                    params: this.params
                }
            })
        }
    }
}
</script>

方案本无优劣,适合才更重要,需综合考虑 产品设计产品使用度服务利用率 等等。例使用度较低应用可将统计与业务混于同一服务以节约成本,使用度较高应用可采取 本地缓存批量上报 以降低服务压力,但批量上报是否加大统计 误差

本文所述仅冰山一角,欢迎大家留言宝贵经验~

2018/12/19 续更

看到几篇不错的文章:

页面跳转时,统计数据丢失问题探讨

Page Lifecycle API 教程


作者:呆恋小喵

我的后花园:https://sunmengyuan.github.io/garden/

我的 github:https://github.com/sunmengyuan

原文链接:https://sunmengyuan.github.io/garden/2018/12/13/trace.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 产品知识面考察 真题 例题分析 例题7.3 DAU代表 。 日用户点击量 月活跃用户数量 日活跃用户数量 网站...
    爱摄影的奥派阅读 12,264评论 4 46
  • 对2016年作总结后,发现自己的文章中有很多是在务虚,很多新入行的童鞋通过私下方式询问了很多比较实际的问题。但在遵...
    dodonet阅读 5,042评论 0 33
  • 在这篇文章里面,我们会对数据采集的一些基本概念进行阐述,然后,会针对目前市面上新增的一些前端埋点技术,如可视化埋点...
    言射手阅读 6,580评论 1 52
  • 中国互联网用户群已经成为世界最大的互联网群体。与此同时,中国互联网网站的发展也历经了几个阶段,从单纯的网络媒体到现...
    零一间阅读 4,223评论 1 41
  • 前言 最近跟同事花了点时间来思考可视化埋点,并没有什么突破性的进展,不过市面上很多关于可视化埋点的技术文章都在讲达...
    daixunry阅读 7,971评论 1 38