# @fle-sdk/event-tracking-web

> event tracking in web

Latest version **1.2.9** (published 2026-01-28) · ISC license · 0 weekly downloads

## Install

```sh
npm install @fle-sdk/event-tracking-web
pnpm add @fle-sdk/event-tracking-web
yarn add @fle-sdk/event-tracking-web
bun add @fle-sdk/event-tracking-web
```

## Health

**Score 55/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.2.9 |
| Published | 2026-01-28 |
| First published | 2021-06-29 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 329.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | 飞象前端团队 |
| Maintainers | libin_pro, chenfangsheng |
| Keywords | event-tracking-web, event, tracking, web |

## Links

- npm: https://www.npmjs.com/package/@fle-sdk/event-tracking-web
- npm.io page: https://npm.io/package/@fle-sdk/event-tracking-web

## Alternatives

- [async-exit-hook](https://npm.io/package/async-exit-hook.md) — 3.7M weekly downloads
- [evnty](https://npm.io/package/evnty.md) — 7.2K weekly downloads
- [eleventy-plugin-asciidoc](https://npm.io/package/eleventy-plugin-asciidoc.md) — 3.5K weekly downloads
- [@jswork/next-get2get](https://npm.io/package/@jswork/next-get2get.md) — 945 weekly downloads
- [@dashersw/axon](https://npm.io/package/@dashersw/axon.md) — 934 weekly downloads

## Recent versions

- 1.2.9 (latest) — 2026-01-28
- 1.2.0-beta.1 (beta) — 2024-03-07
- 1.2.8 — 2026-01-06
- 1.2.7 — 2026-01-04
- 1.2.6 — 2025-12-30
- 1.2.5 — 2025-12-30
- 1.2.4 — 2025-12-30
- 1.2.3 — 2025-12-29
- 1.2.2 — 2025-12-24
- 1.2.1 — 2025-12-22
- 1.2.0 — 2025-12-18
- 1.2.0-beta.0 — 2024-03-04
- 1.1.2-alpha.0 — 2022-05-25
- 1.1.1 — 2021-12-23
- 1.1.0 — 2021-12-22
- … 4 more at https://npm.io/package/@fle-sdk/event-tracking-web/versions

## README

> **构建用户数据体系，让用户行为数据发挥深远的价值。**

**当前版本**: v1.2.4

## 前言

**WEB 数据埋点 sdk，开始之前请确保了解埋点的架构和基础知识**

> 埋点中比较重要的组成部分就是每个事件的 key，注意的是 key 至少由两部分组成。
> 完整的 key 由这几部分组成：appkey.pagekey.partkey 通过“.”来分割

- appkey：APP 应用唯一标识
- pagekey：页面唯一标识，默认取当前路由
- partkey：控件/自定义事件唯一标识，可通过接口获取或自定义

## 一、下载

```jsx
// npm
npm install @fle-sdk/event-tracking-web --save-dev

// yarn
yarn add @fle-sdk/event-tracking-web
```

## 二、全埋点

> 全埋点包括三种事件：Web 页面浏览、Web 元素点击、Web 页面留存时长，对应的配置如下：

```jsx
// 初始化
WebTracking.init({
  appKey: "218844",
  showLog: true,
  autoTrack: true, // 设置该属性之后，SDK 就会自动收集页面浏览事件
  isTrackSinglePage: true,
  contentType: "application/json",
  serverUrl: "https://xxx/push",
});
```

###

### 2.1 元素点击

> 元素的点击事件上报 attr 属性中必须含有 **data-part-key** ，否则会被过滤。

```jsx
// 对充值按钮的点击次数进行统计
<button data-part-key="recharge_btn" data-desc="显示充值弹窗">
  充值
</button>
```

### 2.2 全埋点参数示例

> 全埋点三种类型的上报参数示例，建议都了解一下

```json
{
  "desc": "Web 浏览页面",
  "event": "PageView",
  "itemKey": "218844.app_other",
  "requestTime": 1709524231171,
  "deviceId": "1dd539cdea9332ebb9d5c087f9d4471f",
  "privateParamMap": {
    "currentUrl": "http://localhost:9999/app/other",
    "targetUrl": null,
    "pageWidth": 414,
    "pageHeight": 672,
    "screenWidth": 414,
    "screenHeight": 672,
    "sdkVersion": "1.2.0",
    "systemsInfo": {
      "language": "zh-CN",
      "client": "iPhone, iOS 11.0, WeChat 8.0.5",
      "platform": "h5",
      "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 wechatdevtools/1.06.2310080 MicroMessenger/8.0.5 Language/zh_CN webview/17095233761068527 webdebugger port/25477 token/e60c2e75ed74647fb2c0d949c0a31774"
    },
    "urlParams": {},
    "userInfo": {
      "userId": 20211232232123,
      "userName": "asheng"
    },
    "business": {
      "appId": "1000010"
    }
  }
}
```

```json
{
  "desc": "Web 元素点击",
  "event": "WebClick",
  "itemKey": "218844.main.h1",
  "requestTime": 1709524472904,
  "deviceId": "1dd539cdea9332ebb9d5c087f9d4471f",
  "privateParamMap": {
    "targetEle": {
      "id": "",
      "nodeName": "H1",
      "className": "",
      "position": [66, 108]
    },
    "pointerType": "",
    "currentUrl": "http://localhost:9999/main?a=1",
    "elementSelector": "#root > div:nth-of-type(1) > div:nth-of-type(1) > h1:nth-of-type(1)",
    "pageWidth": 414,
    "pageHeight": 672,
    "screenWidth": 414,
    "screenHeight": 672,
    "sdkVersion": "1.2.0",
    "systemsInfo": {
      "language": "zh-CN",
      "client": "iPhone, iOS 11.0, WeChat 8.0.5",
      "platform": "h5",
      "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 wechatdevtools/1.06.2310080 MicroMessenger/8.0.5 Language/zh_CN webview/17095233761068527 webdebugger port/25477 token/e60c2e75ed74647fb2c0d949c0a31774"
    },
    "urlParams": {
      "a": "1"
    },
    "userInfo": {
      "userId": 20211232232123,
      "userName": "asheng"
    },
    "business": {
      "appId": "1000010"
    }
  }
}
```

```json
{
  "desc": "Web 页面浏览时长",
  "event": "PageRetained",
  "itemKey": "218844.main",
  "requestTime": 1709524334413,
  "deviceId": "1dd539cdea9332ebb9d5c087f9d4471f",
  "privateParamMap": {
    "pageWidth": 414,
    "pageHeight": 672,
    "screenWidth": 414,
    "screenHeight": 672,
    "sdkVersion": "1.2.0",
    "systemsInfo": {
      "language": "zh-CN",
      "client": "iPhone, iOS 11.0, WeChat 8.0.5",
      "platform": "h5",
      "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 wechatdevtools/1.06.2310080 MicroMessenger/8.0.5 Language/zh_CN webview/17095233761068527 webdebugger port/25477 token/e60c2e75ed74647fb2c0d949c0a31774"
    },
    "urlParams": {
      "a": "1"
    },
    "userInfo": {
      "userId": 20211232232123,
      "userName": "asheng"
    },
    "currentUrl": "http://localhost:9999/main?a=1",
    "business": {
      "appId": "1000010"
    },
    "retainedDuration": 103243
  }
}
```

---

## 三、API

WebTracking

- init() ---初始化
- preset() ---配置全局参数（注意：如果配置的全局属性初始化已配置，将覆盖。）
- login() ---用户登录
- track() ---自定义代码埋点上报
- getDeviceId() ---获取设备唯一标识
- resetDeviceId() ---重置设备唯一标识
- setPageKey() ---设置自定义页面唯一标识
- getPageKey() ---获取当前页面唯一标识
- clearBatchTimer() ---清理批量发送定时器
- clearBatchQueue() ---清空批量队列（包括 LocalStorage 中的数据）

### Init

#### 参数

| **参数名**                        | **type**             | **描述**                                                     | **是否必填** | **默认值** |
| --------------------------------- | -------------------- | ------------------------------------------------------------ | ------------ | ---------- |
| appKey                            | string               | 应用唯一标识（由接口生成）                                   | 是           | -          |
| serverUrl                         | string               | 数据接收地址                                                 | 是           | -          |
| autoTrack                         | boolean              | 是否开启全埋点（指的是：页面浏览、元素点击事件自动上报）     | 否           | false      |
| showLog                           | boolean              | 是否在网页控制台打印发送的数据                               | 否           | false      |
| sendTimeout                       | number               | 接口发送超时时长，超过该时长未发送成功将强制取消             | 否           | 3000       |
| isTrackSinglePage                 | boolean              | 是否采集单页面应用的路由变化                                 | 否           | false      |
| contentType                       | string               | application/json                                             |
| application/x-www-form-urlencoded | 否                   | application/x-www-form-urlencoded                            |
| business                          | {[key: string]: any} | 全局自定义业务参数（如果后续手动上报了业务字段，会进行合并） | 否           | -          |
| platform                          | string               | 手动指定应用平台类型                                         | 否           | -          |
| header                            | {[key: string]: any} | 自定义请求头                                                 | 否           | -          |
| sampleRate                        | number               | 数据采样率，0-1 之间，1 表示 100%采样                        | 否           | 1          |
| batchSend                         | boolean              | 是否启用批量发送                                             | 否           | false      |
| batchInterval                     | number               | 批量发送间隔时间(ms)                                         | 否           | 5000       |
| batchMaxSize                      | number               | 批量发送最大数量                                             | 否           | 10         |
| trackPartKeyClick                 | boolean              | 是否对带有 data-part-key 属性的元素点击进行上报（即使 autoTrack 为 false） | 否           | false      |
| pendingRequestsMaxSize            | number               | 待发送请求队列最大数量（防止内存溢出）                       | 否           | 50         |
| sendMethod                        | string               | 数据发送方式：auto（自动选择）、xhr（XMLHttpRequest）、beacon（sendBeacon） | 否           | auto       |
| autoTrackPageDurationInterval    | boolean              | 是否定时上报页面停留时长                                     | 否           | false      |
| pageDurationInterval              | number               | 定时上报页面停留时长的间隔时间（毫秒）                        | 否           | 30000      |
| autoTrackExposure               | boolean              | 是否启用曝光埋点                                             | 否           | false      |
| exposureThreshold              | number               | 曝光进入可视区判定阈值（0-1之间）                            | 否           | 0.5        |
| exposureTime                  | number               | 曝光可见停留时长阈值（毫秒）                                 | 否           | 500        |
| exposureNum                  | number               | 同一元素允许上报的最大曝光次数（不传则不限制）                | 否           | 不限制     |
| pageKey                           | string               | 自定义页面唯一标识，如果不传则自动从路由获取                | 否           | 自动生成   |

#### 例子

> 初始化 sdk 例子，建议在 src/App.js 中初始化，且需在**useLayoutEffect**中初始化。

```jsx
import React, { useLayoutEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const App = () => {
  useLayoutEffect(() => {
    // 初始化埋点
    WebTracking.init({
      appKey: "218844",
      showLog: true,
      autoTrack: true,
      platform: "h5",
      isTrackSinglePage: true,
      serverUrl: "https://qa-gateway.fxqifu.net/pangu/buriedpoint/v2/record/push",
      contentType: "application/json",
      business: {
        appId: "1000010",
      },
      // 数据采样率：0.8 表示 80% 的数据会被上报
      sampleRate: 0.8,
      // 启用批量发送：每 5 秒或达到 10 条数据时批量发送
      batchSend: true,
      batchInterval: 5000,
      batchMaxSize: 10,
      // 自定义页面标识（可选）
      pageKey: "custom_page_key",
    });
  }, []);

  return <div className="App"></div>;
};

export default App;
```

### Preset

> 除了不可配置 appKey、serverUrl，本质上和 init 差不多，这么做是为了更好的区分使用场景，不产生歧义。

#### 参数

| **参数名**                        | **type**             | **描述**                                                 | **是否必填** | **默认值** |
| --------------------------------- | -------------------- | -------------------------------------------------------- | ------------ | ---------- |
| autoTrack                         | boolean              | 是否开启全埋点（指的是：页面浏览、元素点击事件自动上报） | 否           | false      |
| showLog                           | boolean              | 是否在网页控制台打印发送的数据                           | 否           | false      |
| sendTimeout                       | number               | 接口发送超时时长，超过该时长未发送成功将强制取消         | 否           | 3000       |
| isTrackSinglePage                 | boolean              | 是否采集单页面应用的路由变化                             | 否           | false      |
| contentType                       | string               | application/json                                         |
| application/x-www-form-urlencoded | 否                   | application/x-www-form-urlencoded                        |
| business                          | {[key: string]: any} | 手动埋点参数                                             | 否           | {}         |
| platform                          | string               | 手动指定应用平台类型                                     | 否           | -          |
| header                            | {[key: string]: any} | 自定义请求头                                             | 否           | -          |
| sampleRate                        | number               | 数据采样率，0-1 之间，1 表示 100%采样                    | 否           | 1          |
| batchSend                         | boolean              | 是否启用批量发送                                         | 否           | false      |
| batchInterval                     | number               | 批量发送间隔时间(ms)                                     | 否           | 5000       |
| batchMaxSize                      | number               | 批量发送最大数量                                         | 否           | 10         |
| trackPartKeyClick                 | boolean              | 是否对带有 data-part-key 属性的元素点击进行上报（即使 autoTrack 为 false） | 否           | false      |
| pendingRequestsMaxSize            | number               | 待发送请求队列最大数量（防止内存溢出）                   | 否           | 50         |
| sendMethod                        | string               | 数据发送方式：auto（自动选择）、xhr（XMLHttpRequest）、beacon（sendBeacon） | 否           | auto       |
| autoTrackPageDurationInterval    | boolean              | 是否定时上报页面停留时长                                 | 否           | false      |
| pageDurationInterval              | number               | 定时上报页面停留时长的间隔时间（毫秒）                    | 否           | 30000      |
| autoTrackExposure               | boolean              | 是否启用曝光埋点                                         | 否           | false      |
| exposureThreshold              | number               | 曝光进入可视区判定阈值（0-1之间）                        | 否           | 0.5        |
| exposureTime                  | number               | 曝光可见停留时长阈值（毫秒）                             | 否           | 500        |
| exposureNum                  | number               | 同一元素允许上报的最大曝光次数（不传则不限制）            | 否           | 不限制     |
| pageKey                           | string               | 自定义页面唯一标识，如果不传则自动从路由获取            | 否           | 自动生成   |

#### 例子

```jsx
import React, { useLayoutEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const App = () => {
  useLayoutEffect(() => {
    // init tracking
    WebTracking.init({
      appKey: "xxxxxx", // 由接口生成，应用唯一标识
      serverUrl: "https://www.serverHost.com/serverApi/push",
    });

    // 配置全局参数，初始化后预置属性用该方法。
    // 注意：如果配置的全局属性初始化已配置，将覆盖
    WebTracking.preset({
      autoTrack: true,
      showLog: true,
      isTrackSinglePage: true,
      sendTimeout: 10000,
      // 启用批量发送
      batchSend: true,
      batchInterval: 5000,
      batchMaxSize: 10,
      // 设置采样率为 90%
      sampleRate: 0.9,
      // 自定义页面标识（可选）
      pageKey: "home_page",
    });
  }, []);

  const pageHandle = () => {
    WebTracking.preset({
      autoTrack: false, // 关闭全埋点
    });
  };

  return <div className="App" onClick={pageHandle}></div>;
};

export default App;
```

### Login

#### 参数

| 参数名 | type                 | 描述     | 是否必填 | 默认值 |
| ------ | -------------------- | -------- | -------- | ------ |
| params | {[key: string]: any} | 用户信息 | 是       | -      |

#### 例子

```jsx
import React, { useEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";
import { LoginStore } from "store";

const Test = () => {
  const getUserInfo = async () => {
    const userInfo = await LoginStore.getUserInfo();
    // 注意：方法名是 login，不是 Login
    WebTracking.login(userInfo);
  };

  useEffect(() => {
    getUserInfo();
  }, []);

  return <div className="Test"></div>;
};

export default Test;
```

### GetDeviceId

#### 描述

> 获取设备唯一标识。SDK 会基于浏览器指纹技术自动生成设备 ID，并存储在 Cookie 和 LocalStorage 中，确保同一设备在不同会话中保持相同的设备 ID。

#### 返回值

- `string` - 设备唯一标识字符串

#### 例子

```jsx
import React, { useEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Test = () => {
  useEffect(() => {
    // 获取设备ID
    const deviceId = WebTracking.getDeviceId();
    console.log("设备ID:", deviceId);
  }, []);

  return <div className="Test"></div>;
};

export default Test;
```

### ResetDeviceId

#### 描述

> 重置设备唯一标识。清除已存储的设备 ID 并重新生成新的设备 ID。适用于用户切换账号或需要重新标识设备的场景。

#### 返回值

- `string` - 新的设备唯一标识字符串

#### 例子

```jsx
import React from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Test = () => {
  const handleResetDevice = () => {
    // 重置设备ID
    const newDeviceId = WebTracking.resetDeviceId();
    console.log("新设备ID:", newDeviceId);
  };

  return (
    <div className="Test">
      <button onClick={handleResetDevice}>重置设备ID</button>
    </div>
  );
};

export default Test;
```

### ClearBatchTimer

#### 描述

> 清理批量发送定时器。当需要手动触发批量发送或清理定时器时使用。

#### 例子

```jsx
import React from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Test = () => {
  const handleClearTimer = () => {
    // 清理批量发送定时器
    WebTracking.clearBatchTimer();
  };

  return (
    <div className="Test">
      <button onClick={handleClearTimer}>清理定时器</button>
    </div>
  );
};

export default Test;
```

### ClearBatchQueue

#### 描述

> 清空批量队列。清除内存中的队列数据和 LocalStorage 中持久化的队列数据。适用于需要重置批量发送队列的场景。

#### 例子

```jsx
import React from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Test = () => {
  const handleClearQueue = () => {
    // 清空批量队列（包括 LocalStorage 中的数据）
    WebTracking.clearBatchQueue();
  };

  return (
    <div className="Test">
      <button onClick={handleClearQueue}>清空队列</button>
    </div>
  );
};

export default Test;
```

### SetPageKey

#### 描述

> 设置自定义页面唯一标识。设置后，路由变化时不会自动更新 pageKey（除非设置 `autoUpdate: true`）。

#### 参数

| 参数名    | type           | 描述                                                         | 是否必填 | 默认值 |
| --------- | -------------- | ------------------------------------------------------------ | -------- | ------ |
| pageKey   | string \| null | 页面唯一标识，如果传入 null 或空字符串，则恢复自动生成       | 是       | -      |
| autoUpdate | boolean        | 路由变化时是否自动更新（默认：false，使用自定义值后不再自动更新） | 否       | false  |

#### 例子

```jsx
import React from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Test = () => {
  // 设置自定义页面标识
  const handleSetPageKey = () => {
    WebTracking.setPageKey("custom_page_001");
  };

  // 设置自定义页面标识，并允许路由变化时自动更新
  const handleSetPageKeyWithAutoUpdate = () => {
    WebTracking.setPageKey("custom_page_001", true);
  };

  // 恢复自动生成页面标识
  const handleResetPageKey = () => {
    WebTracking.setPageKey(null);
  };

  return (
    <div className="Test">
      <button onClick={handleSetPageKey}>设置自定义页面标识</button>
      <button onClick={handleSetPageKeyWithAutoUpdate}>设置并允许自动更新</button>
      <button onClick={handleResetPageKey}>恢复自动生成</button>
    </div>
  );
};

export default Test;
```

### GetPageKey

#### 描述

> 获取当前页面唯一标识。

#### 返回值

- `string` - 当前页面唯一标识

#### 例子

```jsx
import React, { useEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Test = () => {
  useEffect(() => {
    // 获取当前页面标识
    const pageKey = WebTracking.getPageKey();
    console.log("当前页面标识:", pageKey);
  }, []);

  return <div className="Test"></div>;
};

export default Test;
```

### Track

> 手动代码埋点上报

#### 上报参数

| **参数名** | **type**             | **描述**                                                                                            | **是否必填** | **默认值**     |
| ---------- | -------------------- | --------------------------------------------------------------------------------------------------- | ------------ | -------------- |
| partkey    | numberstring         | 上报事件 Key（由前后端协商定义或由后端接口生成，该应用下需唯一且具有一定意义，例：goods_detail_pv） | 是           | -              |
| desc       | string               | 上报事件描述                                                                                        | 否           | 自定义上报事件 |
| business   | {[key: string]: any} | 上报的业务参数                                                                                      | 否           | -              |
| header     | {[key: string]: any} | 自定义请求头                                                                                        | 否           | -              |

#### 例子

```jsx
import React, { useEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Index = () => {
  const history = useHistory();

  const tracking = () => {
    WebTracking.track({ desc: "我是描述", partkey: "xxx" })
      .then((res) => console.log(res || "上报成功！"))
      .catch((err) => console.log(err || "上报失败！"));
  };

  // 手动上报商品详情浏览量示例
  useEffect(() => {
    WebTracking.track({
      desc: "商品详情PV埋点",
      partkey: "goods_detail_pv",
      business: {
        goodsId: "123",
        goodsName: "测试商品",
      },
    });
  }, []);

  return (
    <div className="index-wrap">
      <button onClick={tracking}>点我，自动上报</button>
    </div>
  );
};

export default Index;
```

### TrackPageDuration

> 手动上报页面停留时长。支持自定义时长或自动计算时长。

#### 参数

| 参数名    | type                      | 描述                                                         | 是否必填 | 默认值 |
| --------- | ------------------------- | ------------------------------------------------------------ | -------- | ------ |
| duration  | number                    | 自定义停留时长（毫秒），如果不传则自动计算                   | 否       | -      |
| options   | TrackPageDurationOptions  | 配置选项                                                     | 否       | -      |
| resetStartTime | boolean              | 是否重置起始时间（手动上报后重置，定时上报不重置）           | 否       | true   |

#### TrackPageDurationOptions

| 参数名    | type                  | 描述                                                         | 是否必填 | 默认值 |
| --------- | --------------------- | ------------------------------------------------------------ | -------- | ------ |
| desc      | string                | 自定义描述                                                   | 否       | "Web 页面浏览时长" |
| business  | {[key: string]: any} | 自定义业务参数                                               | 否       | {}     |
| pageKey   | string                | 自定义页面唯一标识                                           | 否       | 当前页面标识 |
| header    | {[key: string]: any} | 自定义请求头                                                 | 否       | -      |

#### 例子

```jsx
import React, { useEffect } from "react";
import WebTracking from "@fle-sdk/event-tracking-web";

const Index = () => {
  // 手动上报页面停留时长（自动计算）
  const handleReportDuration = () => {
    WebTracking.trackPageDuration()
      .then((res) => console.log("上报成功", res))
      .catch((err) => console.log("上报失败", err));
  };

  // 手动上报页面停留时长（自定义时长）
  const handleReportCustomDuration = () => {
    WebTracking.trackPageDuration(5000, {
      desc: "自定义时长上报",
      business: {
        customField: "value",
      },
    })
      .then((res) => console.log("上报成功", res))
      .catch((err) => console.log("上报失败", err));
  };

  return (
    <div className="index-wrap">
      <button onClick={handleReportDuration}>上报停留时长</button>
      <button onClick={handleReportCustomDuration}>上报自定义时长</button>
    </div>
  );
};

export default Index;
```

## 四、完整参数明细

### 4.1 request 参数明细

| **参数名**                              | **type** | **描述**         | **示例值**                       |
| --------------------------------------- | -------- | ---------------- | -------------------------------- |
| event                                   | string   | 有四种类型的值： |
| PageViewPageRetainedCustomTrackWebClick | -        |
| desc                                    | string   | 埋点事件描述     | -                                |
| itemKey                                 | string   | 当前埋点事件 Key | appkey.pagekey.partkey           |
| requestTime                             | number   | 发送请求事件     | -                                |
| privateParamMap                         | object   | 私有参数         | [查看详情](#mWMBL)               |
| deviceId                                | string   | 设备 ID          | 9ce0159574b00867c7d2c5b200bd2f60 |

#### 4.2.1 privateParamMap 参数明细

| **参数名**       | **type**             | **描述**             | **示例值**                                                          |
| ---------------- | -------------------- | -------------------- | ------------------------------------------------------------------- |
| currentUrl       | string               | 当前 URL             | http://localhost:9999/main                                          |
| targetUrl        | string               | 目标 URL             | http://localhost:9999/app/other                                     |
| business         | {[key: string]: any} | 手动埋点参数         | -                                                                   |
| targetEle        | TargetEleProps       | 触发元素属性         | [查看详情](#YC74u)                                                  |
| pageWidth        | number               | 页面可视区宽度       | 1440                                                                |
| pageHeight       | number               | 页面可视区高度       | 860                                                                 |
| screenWidth      | number               | 显示屏宽度           | 1440                                                                |
| screenHeight     | number               | 显示屏高度           | 860                                                                 |
| pointerType      | string               | 手动触发的指针类型   | mouse、touch、pen                                                   |
| elementSelector  | string               | 触发元素链路         | #root > div:nth-of-type(1) > div:nth-of-type(1) > h1:nth-of-type(1) |
| userInfo         | {[key: string]: any} | 用户信息             | {userName: "啊盛", userId: 1001}                                    |
| urlParams        | {[key: string]: any} | 路由参数             | -                                                                   |
| systemsInfo      | SystemsInfoTypes     | 系统信息             | [查看详情](#VHfQH)                                                  |
| sdkVersion       | string               | 埋点 SDK 版本        | 1.2.0                                                               |
| retainedDuration | number               | 页面停留时长（毫秒） | 2000                                                                |
| deviceId         | string               | 设备唯一标识         | fp_xxx...                                                           |

#### 4.2.2 TargetEleProps 参数明细

| **参数名** | **type**         | **描述**             | **示例值**     |
| ---------- | ---------------- | -------------------- | -------------- |
| nodeName   | string           | dom 节点名称         | BUTTON         |
| id         | string           | id 类名              | main_btn       |
| className  | string           | class 类名           | fx-primary-btn |
| position   | [number, number] | 元素触发位置：[x, y] | [100, 200]     |

#### 4.2.3 SystemsInfoTypes 参数明细

| **参数名**          | **type** | **描述**                                      | **示例值**                                                                                                                |
| ------------------- | -------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| language            | string   | 系统语言                                      | zh-CN                                                                                                                     |
| network             | string   | 网络类型                                      | -                                                                                                                         |
| ua                  | string   | userAgent                                     | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 |
| client              | string   | 客户端（Mac/Android/iPhone/iPad/iPod/WeChat） | Mac, MacOS 10.15.7                                                                                                        |
| platform            | string   | 应用平台类型，如不传会自动获取                |
| 枚举：h5iPadpcother | h5       |

---

## 五、新功能说明

### 5.1 设备 ID 管理

SDK 1.2.0 版本新增了基于浏览器指纹技术的设备 ID 生成和管理功能。

#### 特性

- **自动生成**：基于浏览器指纹信息（UserAgent、屏幕信息、Canvas、WebGL 等）自动生成唯一设备 ID
- **持久化存储**：设备 ID 存储在 Cookie（2 年过期）和 LocalStorage 中，确保同一设备在不同会话中保持相同的设备 ID
- **隐私保护**：所有敏感数据（如 password、token、secret、key 等）会自动过滤为 `***`

#### 使用示例

```jsx
// 获取设备ID
const deviceId = WebTracking.getDeviceId();

// 重置设备ID（适用于用户切换账号等场景）
const newDeviceId = WebTracking.resetDeviceId();
```

### 5.2 批量发送

当埋点数据量较大时，可以使用批量发送功能来减少网络请求次数，提升性能。

#### 配置参数

- `batchSend`: 是否启用批量发送（默认：false）
- `batchInterval`: 批量发送间隔时间，单位毫秒（默认：5000）
- `batchMaxSize`: 批量发送最大数量，达到该数量会立即发送（默认：10）

#### 工作原理

1. 启用批量发送后，所有埋点数据会先加入队列
2. 当队列达到 `batchMaxSize` 时，立即批量发送
3. 或者每隔 `batchInterval` 毫秒自动发送一次
4. 批量发送失败时，数据会自动重新加入队列，避免数据丢失
5. **数据持久化**：队列数据会自动保存到 LocalStorage，页面刷新或关闭后数据不会丢失
6. **自动恢复**：重新打开页面时，会自动从 LocalStorage 恢复未发送的数据并继续发送
7. **数据格式**：批量发送时直接发送数组，不包装在 `events` 参数中

#### 使用示例

```jsx
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  // 启用批量发送
  batchSend: true,
  batchInterval: 5000, // 每5秒发送一次
  batchMaxSize: 10, // 或达到10条数据时立即发送
});
```

#### 数据格式说明

批量发送时，数据直接以数组形式发送，格式如下：

```json
[
  {
    "event": "CustomTrack",
    "desc": "自定义上报事件",
    "itemKey": "218844.page1.event1",
    "requestTime": 1709524231171,
    "deviceId": "1dd539cdea9332ebb9d5c087f9d4471f",
    "privateParamMap": { ... }
  },
  {
    "event": "CustomTrack",
    "desc": "自定义上报事件",
    "itemKey": "218844.page1.event2",
    "requestTime": 1709524231172,
    "deviceId": "1dd539cdea9332ebb9d5c087f9d4471f",
    "privateParamMap": { ... }
  }
]
```

#### 数据持久化说明

- **自动保存**：每次添加数据到队列时，会自动保存到 LocalStorage
- **自动恢复**：初始化时（如果启用了批量发送），会自动从 LocalStorage 恢复未发送的数据
- **页面卸载保护**：页面关闭或刷新时，会自动保存队列数据，确保数据不丢失
- **存储限制**：如果队列数据超过 4MB，会自动截断保留最新的 80% 数据
- **存储位置**：LocalStorage key 为 `web_tracking_batch_queue`

### 5.3 数据采样

当数据量过大时，可以使用数据采样功能来控制上报的数据量，节省服务器资源。

#### 配置参数

- `sampleRate`: 数据采样率，0-1 之间的数字（默认：1）
  - `1`: 100% 采样，所有数据都上报
  - `0.8`: 80% 采样，随机上报 80% 的数据
  - `0.5`: 50% 采样，随机上报 50% 的数据
  - `0`: 0% 采样，不上报任何数据

#### 使用示例

```jsx
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  // 设置采样率为 80%
  sampleRate: 0.8,
});
```

### 5.4 敏感数据过滤

SDK 会自动过滤敏感字段，保护用户隐私。默认会过滤以下字段：

- `password`
- `token`
- `secret`
- `key`

被过滤的字段值会显示为 `***`。

#### 自定义敏感字段

如果需要自定义敏感字段列表，可以在代码中扩展 `filterSensitiveData` 方法。

### 5.5 数据发送方式

SDK 支持三种数据发送方式，可通过 `sendMethod` 参数配置。

#### 配置参数

- `sendMethod`: 数据发送方式（默认：auto）
  - `auto`: 自动选择（推荐）
    - 优先使用 `sendBeacon`（页面卸载时、无自定义请求头时）
    - 否则使用 `XMLHttpRequest`
  - `xhr`: 强制使用 `XMLHttpRequest`
  - `beacon`: 强制使用 `sendBeacon`

#### 工作原理

1. **auto 模式（推荐）**：
   - 支持自定义请求头时使用 `XMLHttpRequest`
   - 不支持自定义请求头时优先使用 `sendBeacon`
   - 页面卸载时自动切换到 `sendBeacon` 确保数据发送
   - `sendBeacon` 失败时自动降级到 `XMLHttpRequest`

2. **xhr 模式**：
   - 始终使用 `XMLHttpRequest` 发送数据
   - 支持自定义请求头
   - 支持超时控制
   - 页面卸载时可能被取消

3. **beacon 模式**：
   - 始终使用 `sendBeacon` 发送数据
   - 不支持自定义请求头
   - 页面卸载时也能可靠发送
   - 无法获取发送结果

#### 使用示例

```jsx
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  // 使用自动模式（推荐）
  sendMethod: "auto",
  // 或者强制使用 XMLHttpRequest
  // sendMethod: "xhr",
  // 或者强制使用 sendBeacon
  // sendMethod: "beacon",
});
```

### 5.6 元素点击追踪

SDK 提供了灵活的元素点击追踪方式，支持全埋点和部分埋点两种模式。

#### 配置参数

- `autoTrack`: 是否开启全埋点（包括页面浏览、元素点击事件自动上报）
- `trackPartKeyClick`: 是否对带有 `data-part-key` 属性的元素点击进行上报（即使 `autoTrack` 为 false）

#### 工作原理

1. **全埋点模式（autoTrack: true）**：
   - 自动追踪所有元素点击事件
   - 自动上报页面浏览事件
   - 支持单页面应用路由变化追踪

2. **部分埋点模式（trackPartKeyClick: true）**：
   - 只追踪带有 `data-part-key` 属性的元素点击
   - 适用于需要精确控制埋点范围的场景
   - 可与 `autoTrack: false` 配合使用

#### 使用示例

```jsx
// 全埋点模式：追踪所有点击
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  autoTrack: true,
});

// 部分埋点模式：只追踪带有 data-part-key 的元素
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  autoTrack: false,
  trackPartKeyClick: true,
});

// HTML 中使用 data-part-key
<button data-part-key="recharge_btn" data-desc="显示充值弹窗">
  充值
</button>
```

### 5.7 页面停留时长定时上报

SDK 支持定时上报页面停留时长，适用于需要持续监控用户停留时长的场景。

#### 配置参数

- `autoTrackPageDurationInterval`: 是否定时上报页面停留时长（默认：false）
- `pageDurationInterval`: 定时上报间隔时间，单位毫秒（默认：30000，即30秒）

#### 工作原理

1. 启用定时上报后，SDK 会启动定时器
2. 每隔指定时间间隔自动上报页面停留时长
3. 只在页面可见时上报（避免后台上报）
4. 定时上报不重置起始时间，数据工程师会进行数据清洗
5. 页面卸载时自动停止定时器

#### 使用示例

```jsx
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  // 启用定时上报页面停留时长
  autoTrackPageDurationInterval: true,
  // 每30秒上报一次
  pageDurationInterval: 30000,
});
```

#### 手动上报 vs 定时上报

- **手动上报**：使用 `trackPageDuration()` 方法，适合在特定时机上报（如页面离开时）
- **定时上报**：使用配置项自动上报，适合持续监控场景

两种方式可以同时使用，互不冲突。

### 5.8 元素曝光埋点

SDK 支持自动监听元素曝光事件，适用于需要追踪元素可见性的场景（如商品卡片曝光、广告曝光等）。

#### 触发条件

仅对包含 `data-exposure="true"` 的 DOM 元素做曝光监听与上报（区分大小写，建议统一为字符串 "true"）。

#### 配置参数

- `autoTrackExposure`: 是否启用曝光埋点（默认：false）
- `exposureThreshold`: 曝光进入可视区判定阈值，0-1之间（默认：0.5）
- `exposureTime`: 曝光可见停留时长阈值，单位毫秒（默认：500）
- `exposureNum`: 同一元素允许上报的最大曝光次数（默认：不限制）

#### 工作原理

1. 使用 `IntersectionObserver` API 判定元素是否进入可视区
2. 元素进入可视区后开始计时
3. 元素离开可视区时，如果可见时长达到 `exposureTime` 阈值，则上报曝光事件
4. 如果设置了 `exposureNum`，同一元素超过该次数后不再上报

#### 上报参数提取

从目标元素（或其祖先节点，按"就近原则"）提取所有 `data-*` 属性作为埋点业务参数，规则如下：

- 属性名从 `data-xxx-yyy` 转为 `xxxYyy`（camelCase）
- 示例：`data-goods-id` → `goodsId`，`data-list-id` → `listId`
- 排除属性：`data-exposure`、`data-part-key`、`data-desc`

#### 使用示例

```jsx
WebTracking.init({
  appKey: "218844",
  serverUrl: "https://xxx/push",
  // 启用曝光埋点
  autoTrackExposure: true,
  // 元素进入可视区 50% 时判定为可见
  exposureThreshold: 0.5,
  // 元素连续可见 500ms 才算一次有效曝光
  exposureTime: 500,
  // 同一元素最多上报 3 次曝光
  exposureNum: 3,
});
```

#### HTML 使用示例

```jsx
<div className="goods-list">
  <div
    data-exposure="true"
    data-part-key="goods_card"
    data-desc="商品卡片曝光"
    data-goods-id="12345"
    data-goods-name="测试商品"
    data-list-id="home_list"
  >
    <img src="goods.jpg" alt="商品图片" />
    <h3>商品名称</h3>
  </div>

  <div
    data-exposure="true"
    data-part-key="ad_banner"
    data-desc="广告横幅曝光"
    data-ad-id="999"
    data-ad-position="top"
  >
    <img src="ad.jpg" alt="广告图片" />
  </div>
</div>
```

#### 上报数据示例

```json
{
  "event": "WebExposure",
  "desc": "商品卡片曝光",
  "itemKey": "218844.home_page.goods_card",
  "requestTime": 1709524231171,
  "deviceId": "1dd539cdea9332ebb9d5c087f9d4471f",
  "privateParamMap": {
    "business": {
      "goodsId": "12345",
      "goodsName": "测试商品",
      "listId": "home_list"
    }
  }
}
```

#### 注意事项

1. **浏览器兼容性**：需要浏览器支持 `IntersectionObserver` 和 `MutationObserver` API，不支持时会自动禁用曝光埋点
2. **性能优化**：SDK 会自动去重，避免重复监听同一元素
3. **动态元素**：自动监听动态添加的曝光元素，无需手动调用
4. **数据提取**：`data-*` 属性会从目标元素向上遍历到 BODY 标签，按"就近原则"提取

---

## 六、版本更新日志

### v1.2.4 (最新)

- ✨ 新增元素曝光埋点功能
  - `autoTrackExposure` - 是否启用曝光埋点
  - `exposureThreshold` - 曝光进入可视区判定阈值（0-1之间）
  - `exposureTime` - 曝光可见停留时长阈值（毫秒）
  - `exposureNum` - 同一元素允许上报的最大曝光次数
  - 使用 `IntersectionObserver` API 判定元素可见性
  - 自动提取 `data-*` 属性作为业务参数
  - 支持自定义曝光次数限制

### v1.2.3

- 🐛 修复批量发送数据格式问题
  - 批量发送时直接发送数组，不再包装在 `events` 参数中
- ✨ 新增页面停留时长手动上报功能
  - `trackPageDuration()` - 手动上报页面停留时长
  - 支持自定义时长或自动计算时长
  - 支持自定义页面标识和业务参数
- ✨ 新增页面停留时长定时上报功能
  - `autoTrackPageDurationInterval` - 是否定时上报页面停留时长
  - `pageDurationInterval` - 定时上报间隔时间（默认30秒）
  - 只在页面可见时上报，避免后台上报
- ✨ 新增数据发送方式配置
  - `sendMethod` - 支持 auto、xhr、beacon 三种模式
  - auto 模式自动选择最佳发送方式（推荐）
  - 页面卸载时自动使用 sendBeacon 确保数据发送
- ✨ 新增元素点击追踪配置
  - `trackPartKeyClick` - 只追踪带有 data-part-key 属性的元素点击
  - 支持与 autoTrack 配合使用，实现灵活的埋点策略

### v1.2.0

- ✨ 新增设备 ID 管理功能（基于浏览器指纹技术）
  - `getDeviceId()` - 获取设备唯一标识
  - `resetDeviceId()` - 重置设备唯一标识
- ✨ 新增页面标识自定义功能
  - `pageKey` - 支持在 init 和 preset 中自定义页面标识
  - `setPageKey()` - 动态设置页面标识
  - `getPageKey()` - 获取当前页面标识
  - 支持恢复自动生成模式
- ✨ 新增批量发送功能，支持批量上报埋点数据
  - `batchSend` - 启用批量发送
  - `batchInterval` - 批量发送间隔时间
  - `batchMaxSize` - 批量发送最大数量
  - **LocalStorage 持久化**：队列数据自动保存，页面刷新不丢失
  - **自动恢复**：重新打开页面时自动恢复未发送的数据
  - `clearBatchQueue()` - 清空批量队列
- ✨ 新增数据采样功能，支持按比例采样上报
  - `sampleRate` - 数据采样率（0-1之间）
- ✨ 新增敏感数据自动过滤功能
  - 自动过滤 password、token、secret、key 等敏感字段
- 🔧 优化类型系统，提升类型安全性
  - 完善 TypeScript 类型定义
  - 新增工具类型和接口
- 🔧 优化错误处理机制
  - 批量发送失败时自动重试
  - 添加队列大小限制，防止内存溢出
- 🔧 优化页面卸载处理
  - 使用 `visibilitychange` 和 `beforeunload` 事件保护数据
  - 支持 `sendBeacon` API 优先发送
- 📝 完善文档和代码注释

### v1.1.0

- 基础功能实现
- 全埋点支持
- 自定义埋点支持

---
_Source: https://npm.io/package/@fle-sdk/event-tracking-web · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
