前端监控之rrweb录制用户行为

一、概述

rrweb 是 'record and replay the web' 的简写,旨在利用现代浏览器所提供的强大 API 录制并回放任意 web 界面中的用户操作。

1.1、为什么要录制用户行为?

前端录制用户行为能够提供有价值的数据,帮助团队从多个角度分析和优化产品,提升用户体验,解决潜在问题,最终促进产品的持续改进和业务的增长。

录制用户行为在前端监控中有以下几个重要原因:

用户体验优化。通过录制用户的行为,可以直观地看到用户在页面上的互动过程,帮助开发团队发现页面设计中的不合理之处,及时调整以提升用户体验。例如,某些页面功能可能导致用户困惑或卡顿,录制能帮助迅速识别并定位问题。

BUG排查和复现问题。当用户遇到某些问题时,直接复现问题往往较为困难。通过录制用户行为,可以重现用户的操作流程,帮助开发人员准确找到导致问题的步骤,从而更加高效地进行修复。

数据分析。通过分析录制的用户行为数据,能够了解用户的操作习惯、使用路径、停留时长等信息。这些数据可以帮助产品团队了解哪些功能是用户最常用的,哪些功能可能存在被忽视的情况,帮助产品优化和决策。

用户行为分析与热图。录制可以结合热图工具,帮助团队分析用户点击、滑动、浏览的区域,这样可以更好地优化页面布局、内容展示等,提高页面的转化率。

记录和回放。录制的行为可以在发生问题后进行回放,提供给QA或开发人员作为问题复现的依据,减少沟通成本。

安全和合规性。有些情况下,监控用户行为可以帮助发现潜在的安全问题,例如恶意操作、作弊行为等。通过记录用户的点击流,可以提供审计和追踪支持。

用户研究与市场调研。通过观察用户行为,能够深入了解用户的使用习惯和需求,为产品迭代和市场决策提供数据支持。

二、实践

实现技术环境Vite+Vue3+Pinia

2.1、安装rrweb

在前端项目目录下使用npm或pnpm(需要先安装pnpm)安装rrweb

bash 复制代码
# 安装rrweb
npm i rrweb --save
# 安装播放器
npm i rrweb-player --save

2.2、实现录制

创建store存储rrweb录制内容,以便回放

./store/rrweb/eventStore.ts

javascript 复制代码
import { defineStore } from 'pinia';
import type { eventWithTime } from '@rrweb/types';

interface EventState {
  events: eventWithTime[];
}
export const useEventStore = defineStore('eventStore', {
  state: (): EventState => ({
    events: []
  }),
  getters: {},
  actions: {
    setEvents(events: eventWithTime[]) {
      this.events = events;
    },
    getEvents() {
      return this.events;
    }
  }
}) as any;

记得在main.ts使用store

javascript 复制代码
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

const app = createApp(App);
app.use(router);
app.use(store);

app.mount('#app');

新建录制操作页面

./views/rrweb/recordScreen.vue

html 复制代码
<template>
  <div id="record">
    <div>
      <el-button type="primary" @click="onStart">开始录制</el-button>
      <el-button type="primary" @click="onStop">结束录制</el-button>
    </div>
    <el-form :model="form" label-width="auto" style="max-width: 600px">
      <el-form-item label="Activity name">
        <el-input v-model="form.name" />
      </el-form-item>
      <el-form-item label="Activity zone">
        <el-select v-model="form.region" placeholder="please select your zone">
          <el-option label="Zone one" value="shanghai" />
          <el-option label="Zone two" value="beijing" />
        </el-select>
      </el-form-item>
      <el-form-item label="Activity time">
        <el-col :span="11">
          <el-date-picker v-model="form.date1" type="date" placeholder="Pick a date" style="width: 100%" />
        </el-col>
        <el-col :span="2" class="text-center">
          <span class="text-gray-500">-</span>
        </el-col>
        <el-col :span="11">
          <el-time-picker v-model="form.date2" placeholder="Pick a time" style="width: 100%" />
        </el-col>
      </el-form-item>
      <el-form-item label="Instant delivery">
        <el-switch v-model="form.delivery" />
      </el-form-item>
      <el-form-item label="Activity type">
        <el-checkbox-group v-model="form.type">
          <el-checkbox value="Online activities" name="type"> Online activities </el-checkbox>
          <el-checkbox value="Promotion activities" name="type"> Promotion activities </el-checkbox>
          <el-checkbox value="Offline activities" name="type"> Offline activities </el-checkbox>
          <el-checkbox value="Simple brand exposure" name="type"> Simple brand exposure </el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="Resources">
        <el-radio-group v-model="form.resource">
          <el-radio value="Sponsor">Sponsor</el-radio>
          <el-radio value="Venue">Venue</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="Activity form">
        <el-input v-model="form.desc" type="textarea" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">Create</el-button>
        <el-button>Cancel</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

录制逻辑部分

html 复制代码
<script lang="ts" setup>
import type { eventWithTime } from '@rrweb/types';
import * as rrweb from 'rrweb'; // 需要禁用浏览器扩展,否则会报错不可用
import { reactive } from 'vue';
import { useEventStore } from '@/store/rrweb/eventStore';

const eventStore = useEventStore();
let events: eventWithTime[] = [];
let stopFn: undefined | (() => void);
// do not use same name with ref
const form = reactive({
  name: '',
  region: '',
  date1: '',
  date2: '',
  delivery: false,
  type: [],
  resource: '',
  desc: ''
});

const onSubmit = () => {
  console.log('submit!');
};
const onStart = () => {
  stopFn = rrweb.record({
    emit(event) {
      console.log('event', JSON.stringify(event));
      events.push(event);
    },
    recordCanvas: true
  });
};
const onStop = () => {
  if (!stopFn) return;
  stopFn();
  eventStore.setEvents(events);
};
</script>

2.3、实现回放

新建播放操作页面

./views/rrweb/playScreen.vue

html 复制代码
<template>
  <div class="play">
    <div class="text-red font-800 h-30 text-center bg-blue-600">dddd</div>
    <el-button type="primary" @click="onPlay">回放</el-button>
    <hr />
    <div id="doPlay"></div>
  </div>
</template>

播放逻辑部分

html 复制代码
<script setup lang="ts">
import rrwebPlayer from 'rrweb-player';
import 'rrweb-player/dist/style.css';
import { useEventStore } from '@/store/rrweb/eventStore';
const eventStore = useEventStore();
let events = eventStore.getEvents();
const onPlay = () => {
  if (events.length === 0) return;
  new rrwebPlayer({
    target: document.querySelector('#doPlay')!,
    props: {
      events
    }
  });
};
</script>

2.4、解决问题

跳转测试rrweb页面失败报错

经过翻阅rrweb的github仓库issue,查明原因是有些浏览器插件会影响rrweb,先关掉所有插件

成功跳转rrweb录制页面

三、效果

点击开始录制,成功打印录制对象

结束录制,跳转播放页面播放录制

四、参考

rrweb/README.zh_CN.md at master · rrweb-io/rrweb

相关推荐
CodeBlossom13 分钟前
javaweb -html -CSS
前端·javascript·html
打小就很皮...1 小时前
HBuilder 发行Android(apk包)全流程指南
前端·javascript·微信小程序
集成显卡2 小时前
PlayWright | 初识微软出品的 WEB 应用自动化测试框架
前端·chrome·测试工具·microsoft·自动化·edge浏览器
前端小趴菜053 小时前
React - 组件通信
前端·react.js·前端框架
Amy_cx3 小时前
在表单输入框按回车页面刷新的问题
前端·elementui
dancing9993 小时前
cocos3.X的oops框架oops-plugin-excel-to-json改进兼容多表单导出功能
前端·javascript·typescript·游戏程序
后海 0_o4 小时前
2025前端微服务 - 无界 的实战应用
前端·微服务·架构
Scabbards_4 小时前
CPT304-2425-S2-Software Engineering II
前端
小满zs4 小时前
Zustand 第二章(状态处理)
前端·react.js
程序猿小D4 小时前
第16节 Node.js 文件系统
linux·服务器·前端·node.js·编辑器·vim