tracking-lib-ott 1.0.13 → 1.0.15
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 +257 -464
- package/dist/index.cjs +186 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +359 -16
- package/dist/index.d.ts +359 -16
- package/dist/index.js +175 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Tracking Library OTT
|
|
2
2
|
|
|
3
|
-
Thư viện tracking events dành cho các dự án OTT (Web,
|
|
4
|
-
npm version patch
|
|
5
|
-
npm publish
|
|
3
|
+
Thư viện tracking events dành cho các dự án OTT (Web, Smart TV).
|
|
6
4
|
|
|
7
5
|
## Cài đặt
|
|
8
6
|
|
|
@@ -12,6 +10,21 @@ npm install tracking-lib-ott
|
|
|
12
10
|
yarn add tracking-lib-ott
|
|
13
11
|
```
|
|
14
12
|
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## API Endpoint
|
|
16
|
+
|
|
17
|
+
| Property | Value |
|
|
18
|
+
| ------------ | --------------------------------- |
|
|
19
|
+
| Method | `POST` |
|
|
20
|
+
| URL | `/v2/event_batch` |
|
|
21
|
+
| Content-Type | `application/json` |
|
|
22
|
+
| Giới hạn | Tối đa **200 events** mỗi request |
|
|
23
|
+
|
|
24
|
+
> **Cơ chế**: Thông tin chung đặt ở cấp top-level, phần sự kiện nằm trong mảng `events`. Server sẽ hợp nhất thông tin chung vào từng event trước khi gửi vào Kafka.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
15
28
|
## Sử dụng cơ bản
|
|
16
29
|
|
|
17
30
|
### 1. Khởi tạo (Init)
|
|
@@ -20,442 +33,322 @@ yarn add tracking-lib-ott
|
|
|
20
33
|
import tracking from "tracking-lib-ott";
|
|
21
34
|
|
|
22
35
|
tracking.init({
|
|
23
|
-
baseURL: "https://api.example.com/
|
|
24
|
-
debug: true,
|
|
36
|
+
baseURL: "https://api.example.com/v2/event_batch",
|
|
37
|
+
debug: true,
|
|
25
38
|
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
// Required fields
|
|
40
|
+
appId: "ONPlus", // ONPlus, ONLiveTV
|
|
41
|
+
packageId: "com.vtvcab.onsportstv",
|
|
42
|
+
sessionId: "uuid-v4-session-id", // Hoặc để trống sẽ tự động tạo từ cookie
|
|
43
|
+
sessionSign: "md5_signature", // MD5(append(session_id, secret_key))
|
|
30
44
|
deviceId: "device-unique-id",
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
app_version: "1.0.0",
|
|
42
|
-
language: "vi",
|
|
43
|
-
country: "VN",
|
|
44
|
-
net_type: "Loại mạng mà khác hàng đang kết nối",
|
|
45
|
+
platform: "SmartTV", // WebPC | WebMobile | SmartTV | AndroidTV
|
|
46
|
+
deviceModel: "Samsung TV 2024",
|
|
47
|
+
deviceBrand: "Samsung",
|
|
48
|
+
events: [],
|
|
49
|
+
userId: -1, // User ID, -1 nếu chưa đăng nhập
|
|
50
|
+
|
|
51
|
+
// Optional fields
|
|
52
|
+
adId: "gaid-or-idfa",
|
|
53
|
+
deviceOsVersion: "17.0",
|
|
54
|
+
sdkVersion: "1.0.0",
|
|
45
55
|
});
|
|
46
56
|
```
|
|
47
57
|
|
|
48
|
-
### 2.
|
|
58
|
+
### 2. Set User Info
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
// Khi user đăng nhập -> set userId
|
|
62
|
+
// userId sẽ tự động được thêm vào mỗi event
|
|
63
|
+
tracking.setUserInfo({ userId: 12345 });
|
|
64
|
+
|
|
65
|
+
// Khi user đăng xuất
|
|
66
|
+
tracking.setUserInfo({ userId: -1 });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. Track Page View
|
|
49
70
|
|
|
50
71
|
```javascript
|
|
51
|
-
// Track khi user vào một trang
|
|
52
72
|
tracking.trackPageView("/home");
|
|
53
73
|
tracking.trackPageView("/detail/123");
|
|
54
74
|
tracking.trackPageView("/live/channel-1");
|
|
55
75
|
```
|
|
56
76
|
|
|
57
|
-
###
|
|
77
|
+
### 4. Track Custom Event
|
|
58
78
|
|
|
59
79
|
```javascript
|
|
60
|
-
// Track event tuỳ ý với params
|
|
61
80
|
tracking.trackEvent("button_click", {
|
|
62
81
|
button_id: "subscribe_btn",
|
|
63
82
|
page_id: "detail",
|
|
64
83
|
});
|
|
65
84
|
|
|
66
|
-
tracking.trackEvent("video_play", {
|
|
67
|
-
video_id: "12345",
|
|
68
|
-
video_title: "Trận đấu hay nhất",
|
|
69
|
-
duration: 3600,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
85
|
tracking.trackEvent("search", {
|
|
73
86
|
keyword: "bóng đá",
|
|
74
87
|
results_count: 25,
|
|
75
88
|
});
|
|
76
89
|
```
|
|
77
90
|
|
|
78
|
-
### 4. Send Event trực tiếp
|
|
79
|
-
|
|
80
|
-
```javascript
|
|
81
|
-
// Gửi event với full control payload
|
|
82
|
-
await tracking.sendEvent({
|
|
83
|
-
event_name: "custom_event",
|
|
84
|
-
custom_field_1: "value1",
|
|
85
|
-
custom_field_2: "value2",
|
|
86
|
-
});
|
|
87
|
-
```
|
|
88
|
-
|
|
89
91
|
---
|
|
90
92
|
|
|
91
|
-
##
|
|
93
|
+
## Video Playback Events
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
Thư viện hỗ trợ các events cho video player:
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
import { useEffect } from "react";
|
|
97
|
-
import { useRouter } from "next/router";
|
|
98
|
-
import tracking from "tracking-lib-ott";
|
|
99
|
-
|
|
100
|
-
function MyApp({ Component, pageProps }) {
|
|
101
|
-
const router = useRouter();
|
|
97
|
+
### Flow tracking video
|
|
102
98
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
user_id: 12345,
|
|
110
|
-
deviceId: "device-id",
|
|
111
|
-
deviceModel: navigator.userAgent,
|
|
112
|
-
deviceBrand: "Web Browser",
|
|
113
|
-
ip_address: "", // Lấy từ API hoặc để trống
|
|
114
|
-
debug: process.env.NODE_ENV === "development",
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// Auto track page views
|
|
118
|
-
const cleanup = tracking.usePageViewTracking(router);
|
|
119
|
-
|
|
120
|
-
return cleanup;
|
|
121
|
-
}, [router]);
|
|
122
|
-
|
|
123
|
-
return <Component {...pageProps} />;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export default MyApp;
|
|
99
|
+
```
|
|
100
|
+
view_content_details → playback_started → playback_progress (định kỳ) → playback_completed
|
|
101
|
+
↘ playback_paused ↔ playback_resumed
|
|
102
|
+
↘ buffer_started → buffer_ended
|
|
103
|
+
↘ quality_changed
|
|
104
|
+
↘ playback_error
|
|
127
105
|
```
|
|
128
106
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
## Session Lifecycle Tracking
|
|
132
|
-
|
|
133
|
-
Thư viện hỗ trợ tự động track session của user:
|
|
134
|
-
|
|
135
|
-
| Event | Khi nào gọi | Mô tả |
|
|
136
|
-
| ------------------ | ------------------------- | ------------------------------ |
|
|
137
|
-
| `session_start` | User mở app | Gọi 1 lần khi init |
|
|
138
|
-
| `session_progress` | Định kỳ (mặc định 5 phút) | Heartbeat khi user đang active |
|
|
139
|
-
| `session_end` | User đóng tab/browser/app | Tự động detect |
|
|
140
|
-
|
|
141
|
-
### Cách sử dụng
|
|
107
|
+
### 1. View Content Details
|
|
142
108
|
|
|
143
109
|
```javascript
|
|
144
|
-
import {
|
|
145
|
-
|
|
110
|
+
import { trackViewContentDetails } from "tracking-lib-ott";
|
|
111
|
+
|
|
112
|
+
trackViewContentDetails(
|
|
113
|
+
"content_123", // contentId
|
|
114
|
+
"Phim ABC", // contentTitle
|
|
115
|
+
0, // contentType: 0=VOD, 1=Event, 2=Channel
|
|
116
|
+
"channel_vtv1", // channelId (optional)
|
|
117
|
+
1755766513, // eventTime (optional)
|
|
118
|
+
);
|
|
119
|
+
```
|
|
146
120
|
|
|
147
|
-
|
|
148
|
-
useEffect(() => {
|
|
149
|
-
// 1. Init tracking trước
|
|
150
|
-
tracking.init({
|
|
151
|
-
baseURL: "https://api.example.com/v1/event_batch",
|
|
152
|
-
sessionId: "session-id", // K cần thêm vì đã trong thư viện đã tự động làm việc đó
|
|
153
|
-
sessionSign: "session-sign",
|
|
154
|
-
// ... other config
|
|
155
|
-
});
|
|
121
|
+
### 2. Playback Started
|
|
156
122
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
123
|
+
```javascript
|
|
124
|
+
import { trackPlaybackStarted } from "tracking-lib-ott";
|
|
125
|
+
|
|
126
|
+
trackPlaybackStarted({
|
|
127
|
+
contentId: "content_123",
|
|
128
|
+
contentTitle: "Phim ABC",
|
|
129
|
+
contentType: 0, // 0=VOD, 1=Live, 2=Channel
|
|
130
|
+
playbackSession: "md5_session_hash", // MD5(content_id + start_timestamp)
|
|
131
|
+
videoQuality: "1080p", // 360p | 480p | 720p | 1080p | 2k | 4k
|
|
132
|
+
startTimestamp: 1755766513,
|
|
133
|
+
startPosition: 0, // Live=0, VOD: 0 nếu mới, >0 nếu resume
|
|
134
|
+
duration: 3600, // Live=-1, VOD=số giây
|
|
135
|
+
// Optional
|
|
136
|
+
channelId: "channel_vtv1",
|
|
137
|
+
subContentId: "program_456",
|
|
138
|
+
subContentTitle: "Thời sự 19h",
|
|
139
|
+
});
|
|
140
|
+
```
|
|
164
141
|
|
|
165
|
-
|
|
166
|
-
return () => {
|
|
167
|
-
tracking.cleanupSession();
|
|
168
|
-
};
|
|
169
|
-
}, []);
|
|
142
|
+
### 3. Playback Progress (gửi định kỳ 5s/25s)
|
|
170
143
|
|
|
171
|
-
|
|
172
|
-
}
|
|
144
|
+
```javascript
|
|
145
|
+
import { trackPlaybackProgress } from "tracking-lib-ott";
|
|
146
|
+
|
|
147
|
+
trackPlaybackProgress({
|
|
148
|
+
contentId: "content_123",
|
|
149
|
+
contentTitle: "Phim ABC",
|
|
150
|
+
contentType: 0,
|
|
151
|
+
playbackSession: "md5_session_hash",
|
|
152
|
+
totalWatchTime: 60, // Tổng thời gian đã xem (giây, không tính pause)
|
|
153
|
+
// Optional
|
|
154
|
+
channelId: "channel_vtv1",
|
|
155
|
+
subContentId: "program_456",
|
|
156
|
+
subContentTitle: "Thời sự 19h",
|
|
157
|
+
});
|
|
173
158
|
```
|
|
174
159
|
|
|
175
|
-
###
|
|
160
|
+
### 4. Playback Completed
|
|
176
161
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
162
|
+
```javascript
|
|
163
|
+
import { trackPlaybackCompleted } from "tracking-lib-ott";
|
|
164
|
+
|
|
165
|
+
trackPlaybackCompleted({
|
|
166
|
+
contentId: "content_123",
|
|
167
|
+
contentTitle: "Phim ABC",
|
|
168
|
+
contentType: 0,
|
|
169
|
+
playbackSession: "md5_session_hash",
|
|
170
|
+
totalWatchTime: 3600,
|
|
171
|
+
// Optional
|
|
172
|
+
channelId: "channel_vtv1",
|
|
173
|
+
subContentId: "program_456",
|
|
174
|
+
subContentTitle: "Thời sự 19h",
|
|
175
|
+
});
|
|
176
|
+
```
|
|
183
177
|
|
|
184
|
-
###
|
|
178
|
+
### 5. Playback Paused / Resumed
|
|
185
179
|
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
180
|
+
```javascript
|
|
181
|
+
import { trackPlaybackPaused, trackPlaybackResumed } from "tracking-lib-ott";
|
|
182
|
+
|
|
183
|
+
// Khi user pause
|
|
184
|
+
trackPlaybackPaused({
|
|
185
|
+
contentId: "content_123",
|
|
186
|
+
contentTitle: "Phim ABC",
|
|
187
|
+
contentType: 0,
|
|
188
|
+
playbackSession: "md5_session_hash",
|
|
189
|
+
positionSec: 120,
|
|
190
|
+
});
|
|
193
191
|
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
// Khi user resume
|
|
193
|
+
trackPlaybackResumed({
|
|
194
|
+
contentId: "content_123",
|
|
195
|
+
contentTitle: "Phim ABC",
|
|
196
|
+
contentType: 0,
|
|
197
|
+
playbackSession: "md5_session_hash",
|
|
198
|
+
positionSec: 120,
|
|
199
|
+
});
|
|
200
|
+
```
|
|
196
201
|
|
|
197
|
-
|
|
198
|
-
{
|
|
199
|
-
"events": [{
|
|
200
|
-
"event_name": "session_progress",
|
|
201
|
-
"event_time": 1705734300000,
|
|
202
|
-
"session_duration": 300000,
|
|
203
|
-
"user_id": "12345"
|
|
202
|
+
### 6. Buffer Started / Ended
|
|
204
203
|
|
|
205
|
-
|
|
206
|
-
}
|
|
204
|
+
```javascript
|
|
205
|
+
import { trackBufferStarted, trackBufferEnded } from "tracking-lib-ott";
|
|
206
|
+
|
|
207
|
+
// Khi bắt đầu buffer
|
|
208
|
+
trackBufferStarted({
|
|
209
|
+
contentId: "content_123",
|
|
210
|
+
contentTitle: "Phim ABC",
|
|
211
|
+
contentType: 0,
|
|
212
|
+
playbackSession: "md5_session_hash",
|
|
213
|
+
videoQuality: "1080p",
|
|
214
|
+
positionSec: 120,
|
|
215
|
+
reason: "network_congestion", // seek_operation | network_congestion
|
|
216
|
+
});
|
|
207
217
|
|
|
208
|
-
//
|
|
209
|
-
{
|
|
210
|
-
"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
218
|
+
// Khi kết thúc buffer
|
|
219
|
+
trackBufferEnded({
|
|
220
|
+
contentId: "content_123",
|
|
221
|
+
contentTitle: "Phim ABC",
|
|
222
|
+
contentType: 0,
|
|
223
|
+
playbackSession: "md5_session_hash",
|
|
224
|
+
videoQuality: "1080p",
|
|
225
|
+
positionSec: 120,
|
|
226
|
+
bufferDurationSec: 3, // Buffer mất 3 giây
|
|
227
|
+
reason: "network_congestion",
|
|
228
|
+
});
|
|
217
229
|
```
|
|
218
230
|
|
|
219
|
-
###
|
|
231
|
+
### 7. Quality Changed
|
|
220
232
|
|
|
221
233
|
```javascript
|
|
222
|
-
import {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
sendSessionEnd(); // Kết thúc session
|
|
235
|
-
|
|
236
|
-
// Kiểm tra trạng thái
|
|
237
|
-
isSessionStarted(); // true/false
|
|
238
|
-
getSessionDuration(); // ms đã chạy
|
|
239
|
-
|
|
240
|
-
// Cập nhật config
|
|
241
|
-
updateSessionConfig({ progressInterval: 10 * 60 * 1000 });
|
|
234
|
+
import { trackQualityChanged } from "tracking-lib-ott";
|
|
235
|
+
|
|
236
|
+
trackQualityChanged({
|
|
237
|
+
contentId: "content_123",
|
|
238
|
+
contentTitle: "Phim ABC",
|
|
239
|
+
contentType: 0,
|
|
240
|
+
playbackSession: "md5_session_hash",
|
|
241
|
+
fromQuality: "480p",
|
|
242
|
+
toQuality: "1080p",
|
|
243
|
+
positionSec: 120,
|
|
244
|
+
reason: "user_selected", // automatic_abr | user_selected
|
|
245
|
+
});
|
|
242
246
|
```
|
|
243
247
|
|
|
244
|
-
###
|
|
245
|
-
|
|
246
|
-
1. **`session_start`**: Gọi tự động khi `initSession()` với `autoStart: true`
|
|
247
|
-
2. **`session_progress`**: Timer chạy định kỳ, chỉ gửi khi tab visible
|
|
248
|
-
3. **`session_end`**: Detect qua `beforeunload` (desktop) và `pagehide` (mobile)
|
|
248
|
+
### 8. Playback Error
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
```javascript
|
|
251
|
+
import { trackPlaybackError } from "tracking-lib-ott";
|
|
252
|
+
|
|
253
|
+
trackPlaybackError({
|
|
254
|
+
contentId: "content_123",
|
|
255
|
+
contentTitle: "Phim ABC",
|
|
256
|
+
contentType: 0, // 0=VOD, 1=Live
|
|
257
|
+
playbackSession: "md5_session_hash",
|
|
258
|
+
errorCode: 404,
|
|
259
|
+
errorMessage: "Video not found",
|
|
260
|
+
errorType: "network_error", // video_playback_error, network_error...
|
|
261
|
+
});
|
|
262
|
+
```
|
|
251
263
|
|
|
252
264
|
---
|
|
253
265
|
|
|
254
|
-
## Session
|
|
255
|
-
|
|
256
|
-
Thư viện hỗ trợ **tự động quản lý `session_id`** thông qua cookie. Nếu bạn không truyền `session_id` khi khởi tạo, thư viện sẽ tự động tạo và lưu vào cookie với thời hạn 30 phút.
|
|
257
|
-
|
|
258
|
-
### Tính năng
|
|
259
|
-
|
|
260
|
-
- ✅ **Tự động tạo** `session_id` nếu không được truyền lên
|
|
261
|
-
- ✅ **Lưu vào cookie** với thời hạn mặc định 30 phút
|
|
262
|
-
- ✅ **Hỗ trợ group domain** (ví dụ: `.example.com`)
|
|
263
|
-
- ✅ **Tự động gia hạn** cookie mỗi khi có event `session_start`
|
|
264
|
-
- ✅ **Persistent** - Session ID được giữ nguyên khi refresh trang trong vòng 30 phút
|
|
265
|
-
|
|
266
|
-
### Cách sử dụng
|
|
266
|
+
## Session Lifecycle Tracking
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
| Event | Khi nào gọi |
|
|
269
|
+
| ------------------ | ------------------------- |
|
|
270
|
+
| `session_start` | User mở app |
|
|
271
|
+
| `session_progress` | Định kỳ (mặc định 5 phút) |
|
|
272
|
+
| `session_end` | User đóng tab/browser/app |
|
|
269
273
|
|
|
270
274
|
```javascript
|
|
271
275
|
import tracking from "tracking-lib-ott";
|
|
272
276
|
|
|
273
|
-
//
|
|
274
|
-
tracking.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
userId: 12345,
|
|
278
|
-
deviceId: "device-unique-id",
|
|
279
|
-
deviceModel: "iPhone 14",
|
|
280
|
-
deviceBrand: "Apple",
|
|
281
|
-
ipAddress: "192.168.1.1",
|
|
277
|
+
// Init session tracking
|
|
278
|
+
tracking.initSession({
|
|
279
|
+
progressInterval: 5 * 60 * 1000, // 5 phút
|
|
280
|
+
autoStart: true,
|
|
282
281
|
debug: true,
|
|
283
282
|
});
|
|
284
283
|
|
|
285
|
-
//
|
|
284
|
+
// Cleanup khi unmount
|
|
285
|
+
tracking.cleanupSession();
|
|
286
286
|
```
|
|
287
287
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
```javascript
|
|
291
|
-
tracking.init({
|
|
292
|
-
baseURL: "https://api.example.com/v1/event_batch",
|
|
293
|
-
sessionSign: "session-signature",
|
|
294
|
-
userId: 12345,
|
|
295
|
-
deviceId: "device-unique-id",
|
|
296
|
-
deviceModel: "iPhone 14",
|
|
297
|
-
deviceBrand: "Apple",
|
|
298
|
-
ipAddress: "192.168.1.1",
|
|
299
|
-
|
|
300
|
-
// Cấu hình cookie tùy chỉnh
|
|
301
|
-
sessionCookieConfig: {
|
|
302
|
-
cookieName: "my_session_id", // Tên cookie (mặc định: _tracking_session_id)
|
|
303
|
-
expirationMinutes: 60, // Thời hạn 60 phút (mặc định: 30)
|
|
304
|
-
domain: ".example.com", // Group domain cho tất cả subdomain
|
|
305
|
-
path: "/", // Cookie path
|
|
306
|
-
sameSite: "Lax", // 'Strict' | 'Lax' | 'None'
|
|
307
|
-
},
|
|
308
|
-
|
|
309
|
-
debug: true,
|
|
310
|
-
});
|
|
311
|
-
```
|
|
288
|
+
---
|
|
312
289
|
|
|
313
|
-
|
|
290
|
+
## Tích hợp Next.js (Pages Router)
|
|
314
291
|
|
|
315
292
|
```javascript
|
|
316
293
|
import { useEffect } from "react";
|
|
294
|
+
import { useRouter } from "next/router";
|
|
317
295
|
import tracking from "tracking-lib-ott";
|
|
318
296
|
|
|
319
297
|
function MyApp({ Component, pageProps }) {
|
|
298
|
+
const router = useRouter();
|
|
299
|
+
|
|
320
300
|
useEffect(() => {
|
|
321
|
-
// 1. Init tracking
|
|
301
|
+
// 1. Init tracking
|
|
322
302
|
tracking.init({
|
|
323
|
-
baseURL:
|
|
324
|
-
|
|
325
|
-
|
|
303
|
+
baseURL: process.env.NEXT_PUBLIC_TRACKING_URL,
|
|
304
|
+
appId: "ONPlus",
|
|
305
|
+
packageId: "com.example.app",
|
|
306
|
+
sessionSign: "session-sign",
|
|
326
307
|
deviceId: "device-id",
|
|
308
|
+
platform: "WebPC",
|
|
327
309
|
deviceModel: navigator.userAgent,
|
|
328
310
|
deviceBrand: "Web Browser",
|
|
329
|
-
|
|
330
|
-
sessionCookieConfig: {
|
|
331
|
-
domain: ".example.com",
|
|
332
|
-
expirationMinutes: 30,
|
|
333
|
-
},
|
|
311
|
+
events: [],
|
|
334
312
|
debug: process.env.NODE_ENV === "development",
|
|
335
313
|
});
|
|
336
314
|
|
|
337
|
-
// 2.
|
|
338
|
-
tracking.
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
});
|
|
315
|
+
// 2. Set user info (after login)
|
|
316
|
+
tracking.setUserInfo({ userId: 12345 });
|
|
317
|
+
|
|
318
|
+
// 3. Auto track page views
|
|
319
|
+
const cleanup = tracking.usePageViewTracking(router);
|
|
320
|
+
|
|
321
|
+
// 4. Init session tracking
|
|
322
|
+
tracking.initSession({ autoStart: true });
|
|
346
323
|
|
|
347
324
|
return () => {
|
|
325
|
+
cleanup?.();
|
|
348
326
|
tracking.cleanupSession();
|
|
349
327
|
};
|
|
350
|
-
}, []);
|
|
328
|
+
}, [router]);
|
|
351
329
|
|
|
352
330
|
return <Component {...pageProps} />;
|
|
353
331
|
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Cookie Configuration Options
|
|
357
|
-
|
|
358
|
-
| Option | Type | Default | Mô tả |
|
|
359
|
-
| ------------------- | --------------------------------- | ---------------------- | --------------------------------------------------------- |
|
|
360
|
-
| `cookieName` | string | `_tracking_session_id` | Tên cookie lưu session_id |
|
|
361
|
-
| `expirationMinutes` | number | `30` | Thời gian hết hạn cookie (phút) |
|
|
362
|
-
| `domain` | string | `""` | Domain cho cookie (hỗ trợ group domain như `.domain.com`) |
|
|
363
|
-
| `path` | string | `"/"` | Cookie path |
|
|
364
|
-
| `sameSite` | `"Strict"` \| `"Lax"` \| `"None"` | `"Lax"` | SameSite attribute |
|
|
365
|
-
|
|
366
|
-
### Cơ chế hoạt động
|
|
367
332
|
|
|
368
|
-
|
|
369
|
-
- Thư viện tạo `session_id` mới (format: `{timestamp}_{random}`)
|
|
370
|
-
- Lưu vào cookie với thời hạn 30 phút
|
|
371
|
-
- Ví dụ: `1737603823000_a8f3d9e2`
|
|
372
|
-
|
|
373
|
-
2. **Refresh trang** (trong vòng 30 phút):
|
|
374
|
-
- Thư viện đọc `session_id` từ cookie
|
|
375
|
-
- Sử dụng lại session_id cũ
|
|
376
|
-
- Không tạo session mới
|
|
377
|
-
|
|
378
|
-
3. **Session Start Event**:
|
|
379
|
-
- Mỗi khi có event `session_start`
|
|
380
|
-
- Cookie được **gia hạn thêm 30 phút** từ thời điểm hiện tại
|
|
381
|
-
- Ví dụ: 9:15 trigger session_start → cookie expires lúc 9:45
|
|
382
|
-
|
|
383
|
-
4. **Sau 30 phút không hoạt động**:
|
|
384
|
-
- Cookie hết hạn và bị xóa
|
|
385
|
-
- Lần truy cập tiếp theo sẽ tạo `session_id` mới
|
|
386
|
-
|
|
387
|
-
### Manual Cookie Management
|
|
388
|
-
|
|
389
|
-
```javascript
|
|
390
|
-
import {
|
|
391
|
-
generateSessionId,
|
|
392
|
-
getCookie,
|
|
393
|
-
setCookie,
|
|
394
|
-
getOrCreateSessionId,
|
|
395
|
-
renewSessionCookie,
|
|
396
|
-
clearSessionCookie,
|
|
397
|
-
} from "tracking-lib-ott";
|
|
398
|
-
|
|
399
|
-
// Tạo session ID mới
|
|
400
|
-
const newSessionId = generateSessionId();
|
|
401
|
-
console.log(newSessionId); // "1737603823000_a8f3d9e2"
|
|
402
|
-
|
|
403
|
-
// Lấy hoặc tạo session ID
|
|
404
|
-
const sessionId = getOrCreateSessionId({
|
|
405
|
-
cookieName: "my_session",
|
|
406
|
-
expirationMinutes: 30,
|
|
407
|
-
domain: ".example.com",
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
// Gia hạn cookie
|
|
411
|
-
renewSessionCookie(sessionId, {
|
|
412
|
-
cookieName: "my_session",
|
|
413
|
-
expirationMinutes: 30,
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
// Xóa cookie
|
|
417
|
-
clearSessionCookie({ cookieName: "my_session" });
|
|
418
|
-
|
|
419
|
-
// Đọc cookie thủ công
|
|
420
|
-
const value = getCookie("my_session");
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### User-Provided Session ID
|
|
424
|
-
|
|
425
|
-
Nếu bạn muốn tự quản lý `session_id`, vẫn có thể truyền vào như trước:
|
|
426
|
-
|
|
427
|
-
```javascript
|
|
428
|
-
tracking.init({
|
|
429
|
-
baseURL: "https://api.example.com/v1/event_batch",
|
|
430
|
-
sessionId: "my-custom-session-id", // Tự cung cấp
|
|
431
|
-
sessionSign: "session-signature",
|
|
432
|
-
// ... other config
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
// Cookie sẽ KHÔNG được tạo khi bạn tự truyền session_id
|
|
333
|
+
export default MyApp;
|
|
436
334
|
```
|
|
437
335
|
|
|
438
336
|
---
|
|
439
337
|
|
|
440
338
|
## Custom Page Mapping
|
|
441
339
|
|
|
442
|
-
Mặc định thư viện có sẵn mapping cho các page phổ biến. Bạn có thể tuỳ chỉnh:
|
|
443
|
-
|
|
444
340
|
```javascript
|
|
445
341
|
tracking.init({
|
|
446
|
-
baseURL: "...",
|
|
447
342
|
// ... other config
|
|
448
|
-
|
|
449
343
|
pageMap: {
|
|
450
|
-
//
|
|
344
|
+
// Override hoặc thêm mới
|
|
451
345
|
phim: { name: "Phim", id: "movie" },
|
|
452
346
|
"the-thao": { name: "Thể thao", id: "sports" },
|
|
453
|
-
"tin-tuc": { name: "Tin tức", id: "news" },
|
|
454
347
|
},
|
|
455
348
|
});
|
|
456
349
|
```
|
|
457
350
|
|
|
458
|
-
**
|
|
351
|
+
**Default page mapping:**
|
|
459
352
|
|
|
460
353
|
| URL Path | Page Name | Page ID |
|
|
461
354
|
| ----------- | --------- | -------- |
|
|
@@ -474,146 +367,46 @@ tracking.init({
|
|
|
474
367
|
|
|
475
368
|
## API Reference
|
|
476
369
|
|
|
477
|
-
###
|
|
478
|
-
|
|
479
|
-
Khởi tạo thư viện với config.
|
|
480
|
-
|
|
481
|
-
| Option | Type | Required | Mô tả |
|
|
482
|
-
| -------------- | ------- | -------- | ----------------------------- |
|
|
483
|
-
| `baseURL` | string | ✅ | URL endpoint để gửi events |
|
|
484
|
-
| `session_id` | string | ✅ | Session ID của user |
|
|
485
|
-
| `session_sign` | string | ✅ | Session signature |
|
|
486
|
-
| `user_id` | number | ✅ | User ID (-1 nếu chưa login) |
|
|
487
|
-
| `deviceId` | string | ✅ | Device unique ID |
|
|
488
|
-
| `deviceModel` | string | ✅ | Tên model thiết bị |
|
|
489
|
-
| `deviceBrand` | string | ✅ | Hãng thiết bị |
|
|
490
|
-
| `ip_address` | string | ✅ | IP address |
|
|
491
|
-
| `debug` | boolean | ❌ | Bật/tắt debug logs |
|
|
492
|
-
| `appName` | string | ❌ | Tên app (default: `app_name`) |
|
|
493
|
-
| `platform` | string | ❌ | Platform (default: `Web`) |
|
|
494
|
-
| `pageMap` | object | ❌ | Custom page mapping |
|
|
495
|
-
|
|
496
|
-
### `tracking.trackPageView(url)`
|
|
497
|
-
|
|
498
|
-
Track sự kiện xem trang.
|
|
499
|
-
|
|
500
|
-
```javascript
|
|
501
|
-
tracking.trackPageView("/detail/123?tab=info");
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
### `tracking.trackEvent(eventName, params)`
|
|
505
|
-
|
|
506
|
-
Track custom event.
|
|
507
|
-
|
|
508
|
-
```javascript
|
|
509
|
-
tracking.trackEvent("video_complete", { video_id: "123" });
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
### `tracking.sendEvent(eventData)`
|
|
513
|
-
|
|
514
|
-
Gửi event trực tiếp với full payload.
|
|
515
|
-
|
|
516
|
-
```javascript
|
|
517
|
-
await tracking.sendEvent({
|
|
518
|
-
event_name: "my_event",
|
|
519
|
-
...customData,
|
|
520
|
-
});
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
### `tracking.usePageViewTracking(router)`
|
|
524
|
-
|
|
525
|
-
Auto track page views cho Next.js Pages Router.
|
|
370
|
+
### TrackingConfig (Required Fields)
|
|
526
371
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
372
|
+
| Field | Type | Giới hạn | Mô tả |
|
|
373
|
+
| ------------- | ------ | -------- | -------------------------------------------------- |
|
|
374
|
+
| `baseURL` | string | - | URL endpoint |
|
|
375
|
+
| `appId` | string | - | ONPlus, ONLiveTV |
|
|
376
|
+
| `packageId` | string | ≤ 125 | Package/Bundle ID |
|
|
377
|
+
| `sessionId` | string | UUID v4 | Session ID |
|
|
378
|
+
| `sessionSign` | string | 16..128 | MD5(append(session_id, secret_key)) |
|
|
379
|
+
| `deviceId` | string | ≤ 125 | Device unique ID |
|
|
380
|
+
| `platform` | string | - | Android, Ios, WebPC, WebMobile, SmartTV, AndroidTV |
|
|
381
|
+
| `deviceModel` | string | ≤ 125 | Model thiết bị |
|
|
382
|
+
| `deviceBrand` | string | ≤ 125 | Hãng thiết bị |
|
|
383
|
+
| `events` | array | - | Mảng events (không rỗng) |
|
|
531
384
|
|
|
532
|
-
|
|
385
|
+
### TrackingConfig (Optional Fields)
|
|
533
386
|
|
|
534
|
-
|
|
387
|
+
| Field | Type | Giới hạn | Mô tả |
|
|
388
|
+
| ----------------- | ------- | -------- | ------------------ |
|
|
389
|
+
| `adId` | string | ≤ 125 | GAID/IDFA |
|
|
390
|
+
| `deviceOsVersion` | string | ≤ 50 | VD: "14", "17.6" |
|
|
391
|
+
| `sdkVersion` | string | ≤ 50 | Phiên bản SDK |
|
|
392
|
+
| `debug` | boolean | - | Bật/tắt debug logs |
|
|
535
393
|
|
|
536
|
-
|
|
394
|
+
> **Lưu ý**: `ip_address` và `carrier_net` KHÔNG cần gửi. Server tự lấy từ header.
|
|
537
395
|
|
|
538
396
|
### Event Object Format
|
|
539
397
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
{
|
|
547
|
-
"event_id": "550e8400-e29b-41d4-a716-446655440000", // UUID v4 tự động sinh
|
|
548
|
-
"event_name": "video_play", // Tách riêng từ eventData
|
|
549
|
-
"event_params": "{\"video_id\":\"123\",\"duration\":3600}", // Các params còn lại được JSON stringify
|
|
550
|
-
"event_time": 1705734000, // Unix timestamp (seconds)
|
|
551
|
-
"user_id": 12345 // Từ config
|
|
552
|
-
}
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
### Batch Request Payload
|
|
556
|
-
|
|
557
|
-
Các events được gom lại và gửi theo batch:
|
|
558
|
-
|
|
559
|
-
```json
|
|
560
|
-
{
|
|
561
|
-
"app_name": "app_name",
|
|
562
|
-
"app_id": "",
|
|
563
|
-
"package_id": "domain.example.com",
|
|
564
|
-
"platform": "Web",
|
|
565
|
-
|
|
566
|
-
"session_id": "1737603823000_a8f3d9e2",
|
|
567
|
-
"session_sign": "md5_signature",
|
|
568
|
-
"user_id": 12345,
|
|
569
|
-
|
|
570
|
-
"device_id": "device-unique-id",
|
|
571
|
-
"device_model": "Chrome 120",
|
|
572
|
-
"device_brand": "Web Browser",
|
|
573
|
-
"ip_address": "192.168.1.1",
|
|
574
|
-
|
|
575
|
-
"events": [
|
|
576
|
-
{
|
|
577
|
-
"event_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
578
|
-
"event_name": "page_view",
|
|
579
|
-
"event_params": "{\"page_id\":\"home\",\"page_path\":\"/home\"}",
|
|
580
|
-
"event_time": 1705734000,
|
|
581
|
-
"user_id": 12345
|
|
582
|
-
},
|
|
583
|
-
{
|
|
584
|
-
"event_id": "550e8400-e29b-41d4-a716-446655440001",
|
|
585
|
-
"event_name": "video_play",
|
|
586
|
-
"event_params": "{\"video_id\":\"123\"}",
|
|
587
|
-
"event_time": 1705734005,
|
|
588
|
-
"user_id": 12345
|
|
589
|
-
}
|
|
590
|
-
]
|
|
591
|
-
}
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
### Giải thích các trường trong Event Object
|
|
595
|
-
|
|
596
|
-
| Trường | Type | Mô tả |
|
|
597
|
-
| -------------- | ------ | -------------------------------------------- |
|
|
598
|
-
| `event_id` | string | UUID v4 unique cho mỗi event |
|
|
599
|
-
| `event_name` | string | Tên event (tách từ eventData) |
|
|
600
|
-
| `event_params` | string | JSON string chứa tất cả params còn lại |
|
|
601
|
-
| `event_time` | number | Unix timestamp (seconds) thời điểm tạo event |
|
|
602
|
-
| `user_id` | number | User ID từ config |
|
|
398
|
+
| Field | Type | Bắt buộc | Mô tả |
|
|
399
|
+
| -------------- | ------ | -------- | --------------------- |
|
|
400
|
+
| `user_id` | bigint | ✅ | -1 nếu chưa đăng nhập |
|
|
401
|
+
| `event_name` | string | ✅ | Tên event (≤ 125) |
|
|
402
|
+
| `event_time` | int | ✅ | Unix seconds |
|
|
403
|
+
| `event_params` | string | ❌ | JSON string (≤ 1024) |
|
|
603
404
|
|
|
604
405
|
---
|
|
605
406
|
|
|
606
|
-
##
|
|
407
|
+
## Publish
|
|
607
408
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
- Mỗi event được gửi đi
|
|
612
|
-
- Lỗi nếu có
|
|
613
|
-
|
|
614
|
-
```javascript
|
|
615
|
-
tracking.init({
|
|
616
|
-
debug: process.env.NODE_ENV === "development",
|
|
617
|
-
// ...
|
|
618
|
-
});
|
|
409
|
+
```bash
|
|
410
|
+
npm version patch
|
|
411
|
+
npm publish
|
|
619
412
|
```
|