埋点(Tracking)
什么是埋点?
简单来说,埋点就是在网站或APP里加一段小代码,用来记录用户的各种操作——比如看了哪个页面、点了哪个按钮、提交了哪个表单等等。这些记录下来的数据会传到分析平台,处理后就能知道用户是怎么用产品的。
埋点的类型
按照不同的收集方式和时机,埋点主要有这几种:
1. 页面埋点
页面埋点是最基础的,就像在每个页面门口装个计数器,记录用户「什么时候来的」「呆了多久」。
// 页面加载完成后,记录用户访问
window.addEventListener("load", () => {
// 发送页面访问数据
trackPageView({
pageName: document.title, // 页面标题
pageUrl: window.location.href, // 页面地址
referrer: document.referrer, // 从哪个页面跳转过来的
timestamp: Date.now(), // 当前时间
});
});
// 页面关闭时,计算并记录停留时间
let startTime = Date.now();
window.addEventListener("beforeunload", () => {
let stayTime = Date.now() - startTime;
// 发送停留时间数据
trackPageStayTime({
pageName: document.title,
pageUrl: window.location.href,
stayTime: stayTime, // 呆了多少毫秒
});
});2. 事件埋点
事件埋点记录用户的具体操作,比如点了登录按钮、提交了注册表单、分享了文章等等。
// 封装一个点击事件的埋点函数
function trackButtonClick(buttonName, buttonType, extraInfo = {}) {
// 发送点击事件数据
trackEvent({
eventType: "click", // 事件类型是点击
eventName: buttonName, // 按钮名字
eventParams: {
buttonType, // 按钮类型
timestamp: Date.now(), // 当前时间
...extraInfo, // 其他额外信息
},
});
}
// 使用示例:提交按钮点击
const submitButton = document.getElementById("submit-button");
submitButton.addEventListener("click", () => {
trackButtonClick("submit-form", "primary", {
formName: "user-registration", // 表单名称
userId: "user123", // 用户ID
});
});3. 曝光埋点
曝光埋点用来记录用户有没有看到页面上的某些元素,比如广告、推荐内容这些。
// 检测元素是否被用户看到
function trackElementExposure(element, elementName, extraInfo = {}) {
// 使用浏览器的IntersectionObserver API来检测元素是否进入视口
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 元素进入视口了,发送曝光事件
trackEvent({
eventType: "exposure", // 事件类型是曝光
eventName: elementName, // 元素名称
eventParams: {
timestamp: Date.now(), // 当前时间
elementId: element.id, // 元素ID
elementClass: element.className, // 元素类名
...extraInfo, // 其他额外信息
},
});
// 只记录一次,停止观察这个元素
observer.unobserve(element);
}
});
},
{
threshold: 0.5, // 元素50%以上进入视口时触发
}
);
// 开始观察这个元素
observer.observe(element);
}
// 使用示例:广告元素曝光
const adElements = document.querySelectorAll(".ad-item");
adElements.forEach((ad, index) => {
trackElementExposure(ad, "advertisement", {
adId: ad.dataset.adId, // 广告ID
adPosition: index + 1, // 广告位置
});
});4. 性能埋点
性能埋点用来记录网站或APP的加载速度等性能指标,比如页面多久能打开、资源加载需要多长时间。
// 页面性能埋点
window.addEventListener("load", () => {
// 获取性能数据
const performanceData = {
navigationStart: performance.timing.navigationStart,
responseEnd: performance.timing.responseEnd,
domComplete: performance.timing.domComplete,
loadEventEnd: performance.timing.loadEventEnd,
// 计算各阶段时间
pageLoadTime:
performance.timing.loadEventEnd - performance.timing.navigationStart,
domReadyTime:
performance.timing.domComplete - performance.timing.domLoading,
networkTime:
performance.timing.responseEnd - performance.timing.navigationStart,
};
// 发送性能数据
trackPerformance({
pageName: document.title,
pageUrl: window.location.href,
performanceMetrics: performanceData,
});
});埋点的实现方式
1. 手动埋点
手动埋点就是开发者在需要记录的地方直接写埋点代码。这种方式灵活,想记哪里就记哪里,但缺点是工作量大,容易漏掉。
// 手动埋点示例:用户登录
function handleUserLogin(username, userId) {
// 登录逻辑
// ...
// 登录成功后,记录登录事件
trackEvent({
eventType: "login", // 事件类型是登录
eventName: "user-login", // 事件名称
eventParams: {
username, // 用户名
userId, // 用户ID
timestamp: Date.now(), // 登录时间
loginMethod: "password", // 登录方式
},
});
}2. 声明式埋点
声明式埋点就是在HTML标签里加一些属性来定义埋点,不用在JavaScript代码里到处写,减少对原有代码的影响。
<!-- 声明式埋点示例 -->
<button
id="submit-button"
data-track="true" <!-- 开启埋点 -->
data-track-event="click" <!-- 跟踪点击事件 -->
data-track-name="submit-form" <!-- 事件名称 -->
data-track-params='{"formName":"user-registration"}' <!-- 额外信息 -->
>
提交
</button>// 声明式埋点解析器:自动处理所有带data-track属性的元素
function initDeclarativeTracking() {
// 找到所有开启了埋点的元素
const trackableElements = document.querySelectorAll('[data-track="true"]');
trackableElements.forEach((element) => {
// 获取埋点配置
const eventType = element.dataset.trackEvent || "click"; // 默认跟踪点击事件
const eventName = element.dataset.trackName;
const eventParams = JSON.parse(element.dataset.trackParams || "{}");
// 添加事件监听器
element.addEventListener(eventType, () => {
trackEvent({
eventType,
eventName,
eventParams: {
timestamp: Date.now(), // 当前时间
elementId: element.id, // 元素ID
elementClass: element.className, // 元素类名
...eventParams, // 合并额外信息
},
});
});
});
}
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", initDeclarativeTracking);3. 可视化埋点
可视化埋点是一种更方便的方式,不用写代码,直接用工具在页面上点选要跟踪的元素就行。这种方式效率高,能减少开发工作量。
常用的可视化埋点工具:
- Google Tag Manager
- Matomo Tag Manager
- 神策分析
- 百度统计
埋点数据的发送方式
1. 图片请求(Pixel Tracking)
这种方式是通过创建一个看不见的图片,把数据放在图片的URL参数里发送给服务器。好处是兼容性好,不用额外的库。
function trackWithPixel(data) {
// 埋点服务器地址
const baseUrl = "https://analytics.example.com/track";
const params = new URLSearchParams();
// 把数据转成URL参数
Object.entries(data).forEach(([key, value]) => {
params.append(key, JSON.stringify(value));
});
// 创建一个看不见的图片元素
const img = new Image();
img.src = `${baseUrl}?${params.toString()}`; // 数据放在URL里
img.style.display = "none";
// 添加到页面,发送请求
document.body.appendChild(img);
// 请求发送后,移除图片元素
img.onload = () => {
document.body.removeChild(img);
};
img.onerror = () => {
document.body.removeChild(img);
};
}2. XMLHttpRequest/Fetch
这种方式用浏览器自带的Fetch API或XMLHttpRequest发送数据。好处是可以发送更复杂的数据,但可能会有跨域问题。
function trackWithFetch(data) {
const url = "https://analytics.example.com/track";
fetch(url, {
method: "POST", // 使用POST请求
headers: {
"Content-Type": "application/json", // 数据格式是JSON
},
body: JSON.stringify(data), // 把数据转成JSON字符串
credentials: "include", // 包含cookies信息
}).catch((error) => {
console.error("埋点请求失败:", error);
});
}3. Beacon API
Beacon API是浏览器的新API,专门用来异步发送小数据,尤其是在页面关闭的时候用最合适,能确保数据发送成功。
function trackWithBeacon(data) {
const url = "https://analytics.example.com/track";
// 检查浏览器是否支持Beacon API
if (navigator.sendBeacon) {
navigator.sendBeacon(url, JSON.stringify(data));
} else {
// 不支持的话,用图片请求作为降级方案
trackWithPixel(data);
}
}
// 页面关闭时,用Beacon API发送离开事件
window.addEventListener("beforeunload", () => {
trackWithBeacon({
eventType: "page-unload",
eventName: "user-leave",
eventParams: {
pageName: document.title,
pageUrl: window.location.href,
timestamp: Date.now(),
},
});
});埋点的最佳实践
1. 先想清楚为什么要埋点
在加埋点之前,先想清楚:我要收集什么数据?收集这些数据用来做什么?别盲目加,不然收集一堆没用的数据。
2. 统一命名规范
大家要约定好埋点的命名规则和数据格式,比如按钮点击事件都叫"button-click-xxx",这样收集到的数据才规整,方便分析。
3. 保护用户隐私
一定要遵守隐私法规(比如GDPR、CCPA),先得到用户同意再收集数据,别收集敏感信息。
// 检查用户是否同意数据收集
function canTrackUser() {
// 从本地存储获取用户的隐私设置
const userPreferences = localStorage.getItem("userPreferences");
if (userPreferences) {
const preferences = JSON.parse(userPreferences);
return preferences.allowTracking === true;
}
return false; // 默认不收集
}
// 发送埋点前先检查用户是否同意
function trackEventWithConsent(eventData) {
if (canTrackUser()) {
trackEvent(eventData);
}
}4. 别影响页面性能
埋点代码要尽量轻量,别拖慢页面加载速度:
- 用异步请求,别阻塞页面加载
- 攒够一定数量的数据再一起发,别每次都单独发请求
- 别在页面刚加载的时候就发一堆埋点请求
- 数据别太大,只传必要的信息
// 批量发送埋点数据:攒够10个再一起发
const trackQueue = []; // 埋点队列
const BATCH_SIZE = 10; // 每次发送10条
let isProcessing = false; // 是否正在发送
// 添加数据到队列
function addToTrackQueue(data) {
trackQueue.push(data);
// 攒够10个或者还没开始发送,就处理队列
if (trackQueue.length >= BATCH_SIZE || !isProcessing) {
processTrackQueue();
}
}
// 处理队列,发送数据
function processTrackQueue() {
// 如果正在发送或者队列为空,就不处理
if (isProcessing || trackQueue.length === 0) return;
isProcessing = true;
// 取出队列里的前10条数据
const batchData = trackQueue.splice(0, BATCH_SIZE);
// 批量发送数据
sendBatchData(batchData)
.then(() => {
isProcessing = false;
// 如果队列里还有数据,继续处理
if (trackQueue.length > 0) {
processTrackQueue();
}
})
.catch(() => {
isProcessing = false;
// 发送失败的话,把数据放回队列开头,下次再试
trackQueue.unshift(...batchData);
});
}常用的埋点工具和库
1. 第三方分析平台
这些平台提供了现成的埋点方案,直接用就行:
- Google Analytics(谷歌分析)
- Matomo (Piwik)(开源分析工具)
- Mixpanel(用户行为分析)
- Amplitude(产品分析)
- 神策分析(国内常用,支持私有化部署)
- 百度统计(适合国内网站)
2. 开源埋点库
如果想要自己定制埋点功能,可以试试这些开源库:
- Segment - 统一的客户数据平台,能对接各种分析工具
- Snowplow - 企业级的,功能很全
- Tracker.js - 轻量级的,适合小项目
- logrocket - 不仅能埋点,还能回放用户的操作过程,方便调试
更新日志
2bd01-于
