onerway-analytics 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -97
- package/dist/bundle/index.js +82 -175
- package/dist/bundle/index.js.map +4 -4
- package/dist/core/analytics.d.ts +4 -5
- package/dist/core/analytics.d.ts.map +1 -1
- package/dist/core/analytics.js +33 -50
- package/dist/core/gtm-loader.d.ts +3 -0
- package/dist/core/gtm-loader.d.ts.map +1 -0
- package/dist/core/gtm-loader.js +38 -0
- package/dist/core/gtm-manager.d.ts +19 -0
- package/dist/core/gtm-manager.d.ts.map +1 -0
- package/dist/core/gtm-manager.js +39 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types/index.d.ts +5 -13
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# onerway-analytics
|
|
2
2
|
|
|
3
|
-
客户端埋点 SDK,支持双发:自建数据服务 + Google
|
|
3
|
+
客户端埋点 SDK,支持双发:自建数据服务 + Google Tag Manager(GTM)。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -14,6 +14,7 @@ npm install onerway-analytics
|
|
|
14
14
|
|
|
15
15
|
```html
|
|
16
16
|
<script src="./dist/bundle/index.js"></script>
|
|
17
|
+
<!-- 全局变量:window.OnrwayAnalytics -->
|
|
17
18
|
```
|
|
18
19
|
|
|
19
20
|
---
|
|
@@ -24,66 +25,58 @@ npm install onerway-analytics
|
|
|
24
25
|
import { createAnalytics } from 'onerway-analytics';
|
|
25
26
|
|
|
26
27
|
const analytics = createAnalytics({
|
|
27
|
-
appKey:
|
|
28
|
-
serverUrl: 'https://your-server.com/collect',
|
|
29
|
-
env:
|
|
30
|
-
debug:
|
|
28
|
+
appKey: 'your-app-key',
|
|
29
|
+
serverUrl: 'https://your-server.com/collect',
|
|
30
|
+
env: 'prod',
|
|
31
|
+
debug: true,
|
|
31
32
|
});
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
### 上报模式
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#### 双发(自建 + GA)
|
|
39
|
-
|
|
40
|
-
同时发送到自建服务和 Google Analytics 4:
|
|
37
|
+
#### 双发(自建服务 + GTM)
|
|
41
38
|
|
|
42
39
|
```ts
|
|
43
40
|
const analytics = createAnalytics({
|
|
44
|
-
appKey:
|
|
41
|
+
appKey: 'your-app-key',
|
|
45
42
|
serverUrl: 'https://your-server.com/collect',
|
|
46
|
-
env:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
enabled:
|
|
50
|
-
sendPageView: false,
|
|
51
|
-
debugMode: true,
|
|
43
|
+
env: 'prod',
|
|
44
|
+
gtm: {
|
|
45
|
+
containerId: 'GTM-XXXXXXX',
|
|
46
|
+
enabled: true,
|
|
52
47
|
},
|
|
53
48
|
});
|
|
54
49
|
```
|
|
55
50
|
|
|
56
51
|
#### 只发自建服务
|
|
57
52
|
|
|
58
|
-
不配置 `
|
|
53
|
+
不配置 `gtm`,或设置 `gtm.enabled: false`:
|
|
59
54
|
|
|
60
55
|
```ts
|
|
61
56
|
const analytics = createAnalytics({
|
|
62
|
-
appKey:
|
|
57
|
+
appKey: 'your-app-key',
|
|
63
58
|
serverUrl: 'https://your-server.com/collect',
|
|
64
|
-
env:
|
|
65
|
-
debug: true,
|
|
59
|
+
env: 'prod',
|
|
66
60
|
});
|
|
67
61
|
```
|
|
68
62
|
|
|
69
|
-
#### 只发
|
|
63
|
+
#### 只发 GTM
|
|
70
64
|
|
|
71
|
-
设置 `disableServer: true`,`serverUrl`
|
|
65
|
+
设置 `disableServer: true`,`serverUrl` 可留空,所有事件只推入 dataLayer:
|
|
72
66
|
|
|
73
67
|
```ts
|
|
74
68
|
const analytics = createAnalytics({
|
|
75
|
-
appKey:
|
|
76
|
-
serverUrl:
|
|
69
|
+
appKey: 'your-app-key',
|
|
70
|
+
serverUrl: '',
|
|
77
71
|
disableServer: true,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
enabled:
|
|
81
|
-
debugMode: true,
|
|
72
|
+
gtm: {
|
|
73
|
+
containerId: 'GTM-XXXXXXX',
|
|
74
|
+
enabled: true,
|
|
82
75
|
},
|
|
83
76
|
});
|
|
84
77
|
```
|
|
85
78
|
|
|
86
|
-
> `disableServer`
|
|
79
|
+
> `disableServer: true` 时,`analytics.flush()` 和重试机制均不生效。
|
|
87
80
|
|
|
88
81
|
---
|
|
89
82
|
|
|
@@ -93,68 +86,58 @@ const analytics = createAnalytics({
|
|
|
93
86
|
|
|
94
87
|
```ts
|
|
95
88
|
// 普通事件(进入缓冲区,定时批量发送)
|
|
96
|
-
analytics.track('
|
|
89
|
+
analytics.track('button_click', { target_id: 'buy_btn', scene: 'product' });
|
|
97
90
|
|
|
98
|
-
//
|
|
91
|
+
// 关键事件(立即发送,不等缓冲区)
|
|
99
92
|
analytics.track('payment_success', { order_id: '456' }, { keyEvent: true });
|
|
100
93
|
```
|
|
101
94
|
|
|
102
95
|
### 用户标识
|
|
103
96
|
|
|
104
97
|
```ts
|
|
105
|
-
// 设置用户 ID
|
|
106
|
-
analytics.identify('user-123', {
|
|
98
|
+
// 设置用户 ID 与属性
|
|
99
|
+
analytics.identify('user-123', { plan: 'pro', email: 'user@example.com' });
|
|
107
100
|
|
|
108
101
|
// 获取用户信息
|
|
109
|
-
analytics.getUserProfile();
|
|
110
|
-
// { userId: 'user-123', anonymousId: 'uuid...', attributes: {
|
|
102
|
+
const profile = analytics.getUserProfile();
|
|
103
|
+
// { userId: 'user-123', anonymousId: 'uuid...', attributes: { plan: 'pro' } }
|
|
104
|
+
|
|
105
|
+
// 重置用户身份
|
|
106
|
+
analytics.reset();
|
|
111
107
|
```
|
|
112
108
|
|
|
113
|
-
###
|
|
109
|
+
### GTM 编程式控制
|
|
114
110
|
|
|
115
111
|
```ts
|
|
116
|
-
//
|
|
117
|
-
analytics.
|
|
112
|
+
// 直接推送自定义数据到 dataLayer
|
|
113
|
+
analytics.gtm.push({ event: 'custom_event', key: 'value' });
|
|
118
114
|
|
|
119
|
-
//
|
|
120
|
-
analytics.
|
|
115
|
+
// 推送带事件名的数据
|
|
116
|
+
analytics.gtm.track('checkout_start', { step: 1 });
|
|
121
117
|
|
|
122
|
-
//
|
|
123
|
-
analytics.
|
|
124
|
-
analytics_storage: 'denied',
|
|
125
|
-
ad_storage: 'denied',
|
|
126
|
-
});
|
|
127
|
-
analytics.ga.consent('update', {
|
|
128
|
-
analytics_storage: 'granted',
|
|
129
|
-
});
|
|
118
|
+
// 设置用户 ID
|
|
119
|
+
analytics.gtm.setUserId('user-123');
|
|
130
120
|
|
|
131
|
-
//
|
|
132
|
-
analytics.
|
|
121
|
+
// 设置用户属性
|
|
122
|
+
analytics.gtm.setUserProperties({ plan: 'pro' });
|
|
133
123
|
```
|
|
134
124
|
|
|
135
125
|
### 其他方法
|
|
136
126
|
|
|
137
127
|
```ts
|
|
138
|
-
// 立即刷新缓冲区
|
|
139
|
-
analytics.
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
-
analytics.
|
|
143
|
-
|
|
144
|
-
// 获取会话 ID / 客户端 ID
|
|
145
|
-
analytics.getSessionId();
|
|
146
|
-
analytics.getClientId();
|
|
147
|
-
|
|
148
|
-
// 设置客户端类型 / 商户语言
|
|
149
|
-
analytics.setClientType('MINI_PROGRAM');
|
|
150
|
-
analytics.setMerchantLanguage('zh');
|
|
128
|
+
analytics.flush(); // 立即刷新缓冲区
|
|
129
|
+
analytics.getSessionId(); // 获取当前 session ID
|
|
130
|
+
analytics.getClientId(); // 获取匿名客户端 ID
|
|
131
|
+
analytics.setClientType('MINI_PROGRAM'); // 设置客户端类型
|
|
132
|
+
analytics.setMerchantLanguage('zh'); // 设置商户语言
|
|
133
|
+
analytics.destroy(); // 销毁实例,移除事件监听(SPA 路由切换时使用)
|
|
151
134
|
```
|
|
152
135
|
|
|
153
136
|
---
|
|
154
137
|
|
|
155
138
|
## 自动埋点
|
|
156
139
|
|
|
157
|
-
默认开启,通过 `data-track-*`
|
|
140
|
+
默认开启,通过 `data-track-*` 属性声明式配置:
|
|
158
141
|
|
|
159
142
|
```html
|
|
160
143
|
<!-- 自定义事件名 -->
|
|
@@ -169,23 +152,48 @@ analytics.setMerchantLanguage('zh');
|
|
|
169
152
|
<!-- 任意 data-track-* 前缀自动成为属性键 -->
|
|
170
153
|
<a data-track-name="share"
|
|
171
154
|
data-track-platform="wechat"
|
|
172
|
-
data-track-position="top">
|
|
173
|
-
分享
|
|
174
|
-
</a>
|
|
155
|
+
data-track-position="top">分享</a>
|
|
175
156
|
|
|
176
157
|
<!-- 忽略该元素 -->
|
|
177
158
|
<div data-track-ignore>不追踪</div>
|
|
178
159
|
```
|
|
179
160
|
|
|
180
|
-
|
|
161
|
+
限定追踪范围:
|
|
181
162
|
|
|
182
163
|
```ts
|
|
183
164
|
createAnalytics({
|
|
184
|
-
serverUrl:
|
|
185
|
-
autoTrackSelector:
|
|
165
|
+
serverUrl: '...',
|
|
166
|
+
autoTrackSelector: '#app', // 只追踪 #app 内的点击
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
关闭自动埋点:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
createAnalytics({ serverUrl: '...', autoTrack: false });
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 采样控制
|
|
179
|
+
|
|
180
|
+
通过 `sampleRate` 控制上报比例,降低高流量场景的服务器压力。决策在每次页面加载时独立进行——命中采样的会话全量上报,未命中的会话全部丢弃(包括 GTM)。
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// 只上报约 10% 的页面会话
|
|
184
|
+
const analytics = createAnalytics({
|
|
185
|
+
appKey: 'your-app-key',
|
|
186
|
+
serverUrl: 'https://your-server.com/collect',
|
|
187
|
+
sampleRate: 0.1,
|
|
186
188
|
});
|
|
187
189
|
```
|
|
188
190
|
|
|
191
|
+
- `sampleRate: 1`(默认)— 全量上报
|
|
192
|
+
- `sampleRate: 0` — 全部丢弃,可用于临时关闭上报
|
|
193
|
+
- `sampleRate: 0.1` — 约 10% 的页面会话上报,每次刷新重新决策
|
|
194
|
+
|
|
195
|
+
> 采样决策作用于整个会话:同一次页面加载内,所有 `track()` 要么全部上报,要么全部丢弃,不会出现部分事件缺失的碎片数据。
|
|
196
|
+
|
|
189
197
|
---
|
|
190
198
|
|
|
191
199
|
## 配置项
|
|
@@ -193,24 +201,100 @@ createAnalytics({
|
|
|
193
201
|
| 配置 | 类型 | 默认值 | 说明 |
|
|
194
202
|
|---|---|---|---|
|
|
195
203
|
| `appKey` | `string` | — | 应用标识 |
|
|
196
|
-
| `serverUrl` | `string` | — |
|
|
197
|
-
| `apiKey` | `string` | — | API Key
|
|
204
|
+
| `serverUrl` | `string` | — | 数据接收端点(`disableServer: true` 时可留空) |
|
|
205
|
+
| `apiKey` | `string` | — | API Key(不填则按 `env` 自动解析) |
|
|
198
206
|
| `env` | `string` | — | 环境:`beta` \| `test` \| `uat` \| `prod` |
|
|
199
|
-
| `debug` | `boolean` | `false` |
|
|
207
|
+
| `debug` | `boolean` | `false` | 开启控制台日志 |
|
|
200
208
|
| `autoTrack` | `boolean` | `true` | 自动点击追踪 |
|
|
209
|
+
| `autoTrackPageView` | `boolean` | `true` | 初始化时自动发送 `page_view`;设为 `false` 可手动控制 |
|
|
201
210
|
| `autoTrackSelector` | `string` | — | 自动埋点的 CSS 选择器范围 |
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
211
|
+
| `sampleRate` | `number` | `1` | 采样率 `0~1`;每次页面加载独立掷骰,`0.1` 表示约 10% 的页面会话上报,`0` 全不报,`1` 全量报 |
|
|
212
|
+
| `system` | `string` | — | 系统标识,写入每条事件 |
|
|
213
|
+
| `domain` | `string` | — | 业务域标识,写入每条事件 |
|
|
214
|
+
| `keyEvents` | `string[]` | — | 关键事件名单,命中的事件立即发送 |
|
|
215
|
+
| `bufferFlushInterval` | `number` | `5000` | 缓冲区定时刷新间隔(ms) |
|
|
216
|
+
| `bufferMaxSize` | `number` | `25` | 缓冲区达到此数量立即刷新 |
|
|
217
|
+
| `maxRetryCount` | `number` | `3` | 发送失败最大重试次数(指数退避) |
|
|
218
|
+
| `sessionTimeout` | `number` | `1800000` | 会话超时(ms),默认 30 分钟 |
|
|
219
|
+
| `performance.enabled` | `boolean` | `true` | Core Web Vitals 采集开关 |
|
|
220
|
+
| `gtm.enabled` | `boolean` | — | GTM 双发开关 |
|
|
221
|
+
| `gtm.containerId` | `string` | — | GTM 容器 ID(`GTM-XXXXXXX` 格式) |
|
|
222
|
+
| `gtm.dataLayerName` | `string` | `'dataLayer'` | 自定义 dataLayer 变量名 |
|
|
223
|
+
| `disableServer` | `boolean` | `false` | 关闭自建服务上报,只推 GTM |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 上报数据结构
|
|
228
|
+
|
|
229
|
+
### 自建服务(批量 POST)
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"client_id": "uuid",
|
|
234
|
+
"user_id": "user-123",
|
|
235
|
+
"session_id": "uuid",
|
|
236
|
+
"user_properties": { "plan": "pro" },
|
|
237
|
+
"context": {
|
|
238
|
+
"sdk_version": "1.0.0",
|
|
239
|
+
"app_key": "your-app-key",
|
|
240
|
+
"browser": { "name": "Chrome", "version": "135" },
|
|
241
|
+
"operating_system": { "name": "Windows", "version": "10" },
|
|
242
|
+
"device_type": "desktop",
|
|
243
|
+
"country": "CN",
|
|
244
|
+
"language": "zh-CN",
|
|
245
|
+
"timezone": "Asia/Shanghai"
|
|
246
|
+
},
|
|
247
|
+
"marketing": {
|
|
248
|
+
"utm_source": "google",
|
|
249
|
+
"utm_medium": "cpc",
|
|
250
|
+
"utm_campaign": "spring_sale",
|
|
251
|
+
"landing_page": "https://example.com/?utm_source=google",
|
|
252
|
+
"referrer_url": "https://google.com"
|
|
253
|
+
},
|
|
254
|
+
"events": [
|
|
255
|
+
{
|
|
256
|
+
"event_id": "uuid",
|
|
257
|
+
"event_name": "button_click",
|
|
258
|
+
"timestamp": 1700000000000,
|
|
259
|
+
"key_event": false,
|
|
260
|
+
"batch_event_index": 0,
|
|
261
|
+
"batch_ordering_id": "1700000000000-1",
|
|
262
|
+
"batch_page_id": "abc-xyz",
|
|
263
|
+
"event_properties": {
|
|
264
|
+
"system": "web",
|
|
265
|
+
"domain": "payment",
|
|
266
|
+
"scene": "product",
|
|
267
|
+
"action": "click",
|
|
268
|
+
"target_type": "button",
|
|
269
|
+
"target_id": "buy_btn",
|
|
270
|
+
"page_url": "https://example.com/product"
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### GTM dataLayer
|
|
278
|
+
|
|
279
|
+
每个 `track()` 调用推入一条:
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"event": "button_click",
|
|
284
|
+
"action": "click",
|
|
285
|
+
"target_id": "buy_btn",
|
|
286
|
+
"session_id": "uuid",
|
|
287
|
+
"page_url": "https://example.com/product",
|
|
288
|
+
"referrer": ""
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
`identify()` 推入:
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{ "userId": "user-123" }
|
|
296
|
+
{ "plan": "pro", "email": "user@example.com" }
|
|
297
|
+
```
|
|
214
298
|
|
|
215
299
|
---
|
|
216
300
|
|
|
@@ -218,20 +302,36 @@ createAnalytics({
|
|
|
218
302
|
|
|
219
303
|
| 采集项 | 说明 |
|
|
220
304
|
|---|---|
|
|
221
|
-
| 点击事件 |
|
|
222
|
-
| 页面浏览 | 初始化时自动发送 `page_view` |
|
|
223
|
-
| JS 错误 | 全局 `window.error` / `unhandledrejection` |
|
|
224
|
-
| Core Web Vitals | LCP / FCP / CLS / INP / TTFB |
|
|
225
|
-
| 设备上下文 | 浏览器、OS
|
|
226
|
-
| 营销归因 | UTM
|
|
305
|
+
| 点击事件 | 自动埋点(`data-track-*`)+ 手动 `analytics.track()` |
|
|
306
|
+
| 页面浏览 | 初始化时自动发送 `page_view`(可通过 `autoTrackPageView: false` 关闭) |
|
|
307
|
+
| JS 错误 | 全局 `window.error` / `unhandledrejection` 自动捕获 |
|
|
308
|
+
| Core Web Vitals | LCP / FCP / CLS / INP / TTFB(`web_vital` 事件) |
|
|
309
|
+
| 设备上下文 | 浏览器、OS、屏幕分辨率、语言、时区、设备类型 |
|
|
310
|
+
| 营销归因 | UTM 参数持久化、落地页、来源 URL(SPA 路由切换后仍保留) |
|
|
227
311
|
|
|
228
312
|
---
|
|
229
313
|
|
|
230
|
-
##
|
|
314
|
+
## 可靠性机制
|
|
231
315
|
|
|
232
|
-
|
|
316
|
+
- **缓冲区 + 批量发送**:事件先入缓冲区,满 `bufferMaxSize` 或到 `bufferFlushInterval` 后批量发送
|
|
317
|
+
- **指数退避重试**:发送失败最多重试 `maxRetryCount` 次,间隔 1s / 2s / 4s…
|
|
318
|
+
- **本地持久化**:超出重试次数的事件写入 localStorage,下次页面加载时自动恢复补发(24 小时内有效)
|
|
319
|
+
- **页面关闭兜底**:`beforeunload` / `pagehide` 时用 `sendBeacon` 发送缓冲区剩余事件
|
|
320
|
+
- **采样控制**:`sampleRate` 在客户端决定是否上报,降低高流量场景的服务器压力
|
|
233
321
|
|
|
234
|
-
|
|
235
|
-
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## SPA 使用建议
|
|
325
|
+
|
|
326
|
+
路由切换时销毁旧实例,重建新实例以正确发送新页面的 `page_view`:
|
|
236
327
|
|
|
237
|
-
|
|
328
|
+
```ts
|
|
329
|
+
// 路由离开时
|
|
330
|
+
analytics.destroy();
|
|
331
|
+
|
|
332
|
+
// 路由进入时
|
|
333
|
+
analytics = createAnalytics({ ... });
|
|
334
|
+
// 或手动控制
|
|
335
|
+
analytics = createAnalytics({ ..., autoTrackPageView: false });
|
|
336
|
+
analytics.track('page_view', { page_url: location.href });
|
|
337
|
+
```
|