当前位置: 首页 > article >正文

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

一、概述

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

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

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

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

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

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

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

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

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

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

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

二、实践

实现技术环境Vite+Vue3+Pinia

2.1、安装rrweb

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

# 安装rrweb
npm i rrweb --save
# 安装播放器
npm i rrweb-player --save

2.2、实现录制

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

./store/rrweb/eventStore.ts

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

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

<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>

录制逻辑部分

<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

<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>

播放逻辑部分

<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


http://www.kler.cn/a/521833.html

相关文章:

  • SQL注入漏洞之高阶手法 宽字节注入以及编码解释 以及堆叠注入原理说明
  • NoSQL与SQL比较
  • C++ ——— 仿函数
  • CMAKE工程编译好后自动把可执行文件传输到远程开发板
  • 团体程序设计天梯赛-练习集——L1-025 正整数A+B
  • HTML<kbd>标签
  • 【学术会议征稿】第五届能源、电力与先进热力系统学术会议(EPATS 2025)
  • 18. 四数之和【力扣】——两层循环后的双指针法
  • 开启eslint后,html中全角符号绕过eslint检测
  • .NET Core 中依赖注入的使用
  • 上位机知识篇---CMake
  • download-git-repo 一款命令行下载仓库依赖
  • DeepSeek崛起:中国AI新星如何撼动全球资本市场格局
  • PHP中的获取器和修改器:探索数据访问的新维度
  • H3CNE-23-vlan间路由
  • 《企业应用架构模式》笔记
  • YOLOv11-ultralytics-8.3.67部分代码阅读笔记-transformer.py
  • Web3.0时代的挑战与机遇:以开源2+1链动模式AI智能名片S2B2C商城小程序为例的深度探讨
  • 算法-接雨水
  • 第05章 10 地形梯度场模拟显示
  • RGB ByteBuffer 转换成 Bitmap
  • 深度剖析C++17中的std::optional:处理可能缺失值的利器
  • Flutter使用Flavor实现切换环境和多渠道打包
  • Linux网络之序列化和反序列化
  • 无人机红外热成像:应急消防的“透视眼”
  • 实验一---典型环节及其阶跃响应---自动控制原理实验课