tracking-lib-ott 1.0.13 → 1.0.14
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 +256 -464
- package/dist/index.cjs +186 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +358 -16
- package/dist/index.d.ts +358 -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,321 @@ 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
|
-
os_version: "17.0",
|
|
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
|
+
|
|
50
|
+
// Optional fields
|
|
51
|
+
adId: "gaid-or-idfa",
|
|
52
|
+
deviceOsVersion: "17.0",
|
|
53
|
+
sdkVersion: "1.0.0",
|
|
45
54
|
});
|
|
46
55
|
```
|
|
47
56
|
|
|
48
|
-
### 2.
|
|
57
|
+
### 2. Set User Info
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// Khi user đăng nhập -> set userId
|
|
61
|
+
// userId sẽ tự động được thêm vào mỗi event
|
|
62
|
+
tracking.setUserInfo({ userId: 12345 });
|
|
63
|
+
|
|
64
|
+
// Khi user đăng xuất
|
|
65
|
+
tracking.setUserInfo({ userId: -1 });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. Track Page View
|
|
49
69
|
|
|
50
70
|
```javascript
|
|
51
|
-
// Track khi user vào một trang
|
|
52
71
|
tracking.trackPageView("/home");
|
|
53
72
|
tracking.trackPageView("/detail/123");
|
|
54
73
|
tracking.trackPageView("/live/channel-1");
|
|
55
74
|
```
|
|
56
75
|
|
|
57
|
-
###
|
|
76
|
+
### 4. Track Custom Event
|
|
58
77
|
|
|
59
78
|
```javascript
|
|
60
|
-
// Track event tuỳ ý với params
|
|
61
79
|
tracking.trackEvent("button_click", {
|
|
62
80
|
button_id: "subscribe_btn",
|
|
63
81
|
page_id: "detail",
|
|
64
82
|
});
|
|
65
83
|
|
|
66
|
-
tracking.trackEvent("video_play", {
|
|
67
|
-
video_id: "12345",
|
|
68
|
-
video_title: "Trận đấu hay nhất",
|
|
69
|
-
duration: 3600,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
84
|
tracking.trackEvent("search", {
|
|
73
85
|
keyword: "bóng đá",
|
|
74
86
|
results_count: 25,
|
|
75
87
|
});
|
|
76
88
|
```
|
|
77
89
|
|
|
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
90
|
---
|
|
90
91
|
|
|
91
|
-
##
|
|
92
|
+
## Video Playback Events
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
Thư viện hỗ trợ các events cho video player:
|
|
94
95
|
|
|
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();
|
|
96
|
+
### Flow tracking video
|
|
102
97
|
|
|
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;
|
|
98
|
+
```
|
|
99
|
+
view_content_details → playback_started → playback_progress (định kỳ) → playback_completed
|
|
100
|
+
↘ playback_paused ↔ playback_resumed
|
|
101
|
+
↘ buffer_started → buffer_ended
|
|
102
|
+
↘ quality_changed
|
|
103
|
+
↘ playback_error
|
|
127
104
|
```
|
|
128
105
|
|
|
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
|
|
106
|
+
### 1. View Content Details
|
|
142
107
|
|
|
143
108
|
```javascript
|
|
144
|
-
import {
|
|
145
|
-
|
|
109
|
+
import { trackViewContentDetails } from "tracking-lib-ott";
|
|
110
|
+
|
|
111
|
+
trackViewContentDetails(
|
|
112
|
+
"content_123", // contentId
|
|
113
|
+
"Phim ABC", // contentTitle
|
|
114
|
+
0, // contentType: 0=VOD, 1=Event, 2=Channel
|
|
115
|
+
"channel_vtv1", // channelId (optional)
|
|
116
|
+
1755766513, // eventTime (optional)
|
|
117
|
+
);
|
|
118
|
+
```
|
|
146
119
|
|
|
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
|
-
});
|
|
120
|
+
### 2. Playback Started
|
|
156
121
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
122
|
+
```javascript
|
|
123
|
+
import { trackPlaybackStarted } from "tracking-lib-ott";
|
|
124
|
+
|
|
125
|
+
trackPlaybackStarted({
|
|
126
|
+
contentId: "content_123",
|
|
127
|
+
contentTitle: "Phim ABC",
|
|
128
|
+
contentType: 0, // 0=VOD, 1=Live, 2=Channel
|
|
129
|
+
playbackSession: "md5_session_hash", // MD5(content_id + start_timestamp)
|
|
130
|
+
videoQuality: "1080p", // 360p | 480p | 720p | 1080p | 2k | 4k
|
|
131
|
+
startTimestamp: 1755766513,
|
|
132
|
+
startPosition: 0, // Live=0, VOD: 0 nếu mới, >0 nếu resume
|
|
133
|
+
duration: 3600, // Live=-1, VOD=số giây
|
|
134
|
+
// Optional
|
|
135
|
+
channelId: "channel_vtv1",
|
|
136
|
+
subContentId: "program_456",
|
|
137
|
+
subContentTitle: "Thời sự 19h",
|
|
138
|
+
});
|
|
139
|
+
```
|
|
164
140
|
|
|
165
|
-
|
|
166
|
-
return () => {
|
|
167
|
-
tracking.cleanupSession();
|
|
168
|
-
};
|
|
169
|
-
}, []);
|
|
141
|
+
### 3. Playback Progress (gửi định kỳ 5s/25s)
|
|
170
142
|
|
|
171
|
-
|
|
172
|
-
}
|
|
143
|
+
```javascript
|
|
144
|
+
import { trackPlaybackProgress } from "tracking-lib-ott";
|
|
145
|
+
|
|
146
|
+
trackPlaybackProgress({
|
|
147
|
+
contentId: "content_123",
|
|
148
|
+
contentTitle: "Phim ABC",
|
|
149
|
+
contentType: 0,
|
|
150
|
+
playbackSession: "md5_session_hash",
|
|
151
|
+
totalWatchTime: 60, // Tổng thời gian đã xem (giây, không tính pause)
|
|
152
|
+
// Optional
|
|
153
|
+
channelId: "channel_vtv1",
|
|
154
|
+
subContentId: "program_456",
|
|
155
|
+
subContentTitle: "Thời sự 19h",
|
|
156
|
+
});
|
|
173
157
|
```
|
|
174
158
|
|
|
175
|
-
###
|
|
159
|
+
### 4. Playback Completed
|
|
176
160
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
161
|
+
```javascript
|
|
162
|
+
import { trackPlaybackCompleted } from "tracking-lib-ott";
|
|
163
|
+
|
|
164
|
+
trackPlaybackCompleted({
|
|
165
|
+
contentId: "content_123",
|
|
166
|
+
contentTitle: "Phim ABC",
|
|
167
|
+
contentType: 0,
|
|
168
|
+
playbackSession: "md5_session_hash",
|
|
169
|
+
totalWatchTime: 3600,
|
|
170
|
+
// Optional
|
|
171
|
+
channelId: "channel_vtv1",
|
|
172
|
+
subContentId: "program_456",
|
|
173
|
+
subContentTitle: "Thời sự 19h",
|
|
174
|
+
});
|
|
175
|
+
```
|
|
183
176
|
|
|
184
|
-
###
|
|
177
|
+
### 5. Playback Paused / Resumed
|
|
185
178
|
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
179
|
+
```javascript
|
|
180
|
+
import { trackPlaybackPaused, trackPlaybackResumed } from "tracking-lib-ott";
|
|
181
|
+
|
|
182
|
+
// Khi user pause
|
|
183
|
+
trackPlaybackPaused({
|
|
184
|
+
contentId: "content_123",
|
|
185
|
+
contentTitle: "Phim ABC",
|
|
186
|
+
contentType: 0,
|
|
187
|
+
playbackSession: "md5_session_hash",
|
|
188
|
+
positionSec: 120,
|
|
189
|
+
});
|
|
193
190
|
|
|
194
|
-
|
|
195
|
-
|
|
191
|
+
// Khi user resume
|
|
192
|
+
trackPlaybackResumed({
|
|
193
|
+
contentId: "content_123",
|
|
194
|
+
contentTitle: "Phim ABC",
|
|
195
|
+
contentType: 0,
|
|
196
|
+
playbackSession: "md5_session_hash",
|
|
197
|
+
positionSec: 120,
|
|
198
|
+
});
|
|
199
|
+
```
|
|
196
200
|
|
|
197
|
-
|
|
198
|
-
{
|
|
199
|
-
"events": [{
|
|
200
|
-
"event_name": "session_progress",
|
|
201
|
-
"event_time": 1705734300000,
|
|
202
|
-
"session_duration": 300000,
|
|
203
|
-
"user_id": "12345"
|
|
201
|
+
### 6. Buffer Started / Ended
|
|
204
202
|
|
|
205
|
-
|
|
206
|
-
}
|
|
203
|
+
```javascript
|
|
204
|
+
import { trackBufferStarted, trackBufferEnded } from "tracking-lib-ott";
|
|
205
|
+
|
|
206
|
+
// Khi bắt đầu buffer
|
|
207
|
+
trackBufferStarted({
|
|
208
|
+
contentId: "content_123",
|
|
209
|
+
contentTitle: "Phim ABC",
|
|
210
|
+
contentType: 0,
|
|
211
|
+
playbackSession: "md5_session_hash",
|
|
212
|
+
videoQuality: "1080p",
|
|
213
|
+
positionSec: 120,
|
|
214
|
+
reason: "network_congestion", // seek_operation | network_congestion
|
|
215
|
+
});
|
|
207
216
|
|
|
208
|
-
//
|
|
209
|
-
{
|
|
210
|
-
"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
// Khi kết thúc buffer
|
|
218
|
+
trackBufferEnded({
|
|
219
|
+
contentId: "content_123",
|
|
220
|
+
contentTitle: "Phim ABC",
|
|
221
|
+
contentType: 0,
|
|
222
|
+
playbackSession: "md5_session_hash",
|
|
223
|
+
videoQuality: "1080p",
|
|
224
|
+
positionSec: 120,
|
|
225
|
+
bufferDurationSec: 3, // Buffer mất 3 giây
|
|
226
|
+
reason: "network_congestion",
|
|
227
|
+
});
|
|
217
228
|
```
|
|
218
229
|
|
|
219
|
-
###
|
|
230
|
+
### 7. Quality Changed
|
|
220
231
|
|
|
221
232
|
```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 });
|
|
233
|
+
import { trackQualityChanged } from "tracking-lib-ott";
|
|
234
|
+
|
|
235
|
+
trackQualityChanged({
|
|
236
|
+
contentId: "content_123",
|
|
237
|
+
contentTitle: "Phim ABC",
|
|
238
|
+
contentType: 0,
|
|
239
|
+
playbackSession: "md5_session_hash",
|
|
240
|
+
fromQuality: "480p",
|
|
241
|
+
toQuality: "1080p",
|
|
242
|
+
positionSec: 120,
|
|
243
|
+
reason: "user_selected", // automatic_abr | user_selected
|
|
244
|
+
});
|
|
242
245
|
```
|
|
243
246
|
|
|
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)
|
|
247
|
+
### 8. Playback Error
|
|
249
248
|
|
|
250
|
-
|
|
249
|
+
```javascript
|
|
250
|
+
import { trackPlaybackError } from "tracking-lib-ott";
|
|
251
|
+
|
|
252
|
+
trackPlaybackError({
|
|
253
|
+
contentId: "content_123",
|
|
254
|
+
contentTitle: "Phim ABC",
|
|
255
|
+
contentType: 0, // 0=VOD, 1=Live
|
|
256
|
+
playbackSession: "md5_session_hash",
|
|
257
|
+
errorCode: 404,
|
|
258
|
+
errorMessage: "Video not found",
|
|
259
|
+
errorType: "network_error", // video_playback_error, network_error...
|
|
260
|
+
});
|
|
261
|
+
```
|
|
251
262
|
|
|
252
263
|
---
|
|
253
264
|
|
|
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
|
|
265
|
+
## Session Lifecycle Tracking
|
|
267
266
|
|
|
268
|
-
|
|
267
|
+
| Event | Khi nào gọi |
|
|
268
|
+
| ------------------ | ------------------------- |
|
|
269
|
+
| `session_start` | User mở app |
|
|
270
|
+
| `session_progress` | Định kỳ (mặc định 5 phút) |
|
|
271
|
+
| `session_end` | User đóng tab/browser/app |
|
|
269
272
|
|
|
270
273
|
```javascript
|
|
271
274
|
import tracking from "tracking-lib-ott";
|
|
272
275
|
|
|
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",
|
|
276
|
+
// Init session tracking
|
|
277
|
+
tracking.initSession({
|
|
278
|
+
progressInterval: 5 * 60 * 1000, // 5 phút
|
|
279
|
+
autoStart: true,
|
|
282
280
|
debug: true,
|
|
283
281
|
});
|
|
284
282
|
|
|
285
|
-
//
|
|
283
|
+
// Cleanup khi unmount
|
|
284
|
+
tracking.cleanupSession();
|
|
286
285
|
```
|
|
287
286
|
|
|
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
|
-
```
|
|
287
|
+
---
|
|
312
288
|
|
|
313
|
-
|
|
289
|
+
## Tích hợp Next.js (Pages Router)
|
|
314
290
|
|
|
315
291
|
```javascript
|
|
316
292
|
import { useEffect } from "react";
|
|
293
|
+
import { useRouter } from "next/router";
|
|
317
294
|
import tracking from "tracking-lib-ott";
|
|
318
295
|
|
|
319
296
|
function MyApp({ Component, pageProps }) {
|
|
297
|
+
const router = useRouter();
|
|
298
|
+
|
|
320
299
|
useEffect(() => {
|
|
321
|
-
// 1. Init tracking
|
|
300
|
+
// 1. Init tracking
|
|
322
301
|
tracking.init({
|
|
323
|
-
baseURL:
|
|
324
|
-
|
|
325
|
-
|
|
302
|
+
baseURL: process.env.NEXT_PUBLIC_TRACKING_URL,
|
|
303
|
+
appId: "ONPlus",
|
|
304
|
+
packageId: "com.example.app",
|
|
305
|
+
sessionSign: "session-sign",
|
|
326
306
|
deviceId: "device-id",
|
|
307
|
+
platform: "WebPC",
|
|
327
308
|
deviceModel: navigator.userAgent,
|
|
328
309
|
deviceBrand: "Web Browser",
|
|
329
|
-
|
|
330
|
-
sessionCookieConfig: {
|
|
331
|
-
domain: ".example.com",
|
|
332
|
-
expirationMinutes: 30,
|
|
333
|
-
},
|
|
310
|
+
events: [],
|
|
334
311
|
debug: process.env.NODE_ENV === "development",
|
|
335
312
|
});
|
|
336
313
|
|
|
337
|
-
// 2.
|
|
338
|
-
tracking.
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
});
|
|
314
|
+
// 2. Set user info (after login)
|
|
315
|
+
tracking.setUserInfo({ userId: 12345 });
|
|
316
|
+
|
|
317
|
+
// 3. Auto track page views
|
|
318
|
+
const cleanup = tracking.usePageViewTracking(router);
|
|
319
|
+
|
|
320
|
+
// 4. Init session tracking
|
|
321
|
+
tracking.initSession({ autoStart: true });
|
|
346
322
|
|
|
347
323
|
return () => {
|
|
324
|
+
cleanup?.();
|
|
348
325
|
tracking.cleanupSession();
|
|
349
326
|
};
|
|
350
|
-
}, []);
|
|
327
|
+
}, [router]);
|
|
351
328
|
|
|
352
329
|
return <Component {...pageProps} />;
|
|
353
330
|
}
|
|
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
331
|
|
|
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
|
|
332
|
+
export default MyApp;
|
|
436
333
|
```
|
|
437
334
|
|
|
438
335
|
---
|
|
439
336
|
|
|
440
337
|
## Custom Page Mapping
|
|
441
338
|
|
|
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
339
|
```javascript
|
|
445
340
|
tracking.init({
|
|
446
|
-
baseURL: "...",
|
|
447
341
|
// ... other config
|
|
448
|
-
|
|
449
342
|
pageMap: {
|
|
450
|
-
//
|
|
343
|
+
// Override hoặc thêm mới
|
|
451
344
|
phim: { name: "Phim", id: "movie" },
|
|
452
345
|
"the-thao": { name: "Thể thao", id: "sports" },
|
|
453
|
-
"tin-tuc": { name: "Tin tức", id: "news" },
|
|
454
346
|
},
|
|
455
347
|
});
|
|
456
348
|
```
|
|
457
349
|
|
|
458
|
-
**
|
|
350
|
+
**Default page mapping:**
|
|
459
351
|
|
|
460
352
|
| URL Path | Page Name | Page ID |
|
|
461
353
|
| ----------- | --------- | -------- |
|
|
@@ -474,146 +366,46 @@ tracking.init({
|
|
|
474
366
|
|
|
475
367
|
## API Reference
|
|
476
368
|
|
|
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.
|
|
369
|
+
### TrackingConfig (Required Fields)
|
|
526
370
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
371
|
+
| Field | Type | Giới hạn | Mô tả |
|
|
372
|
+
| ------------- | ------ | -------- | -------------------------------------------------- |
|
|
373
|
+
| `baseURL` | string | - | URL endpoint |
|
|
374
|
+
| `appId` | string | - | ONPlus, ONLiveTV |
|
|
375
|
+
| `packageId` | string | ≤ 125 | Package/Bundle ID |
|
|
376
|
+
| `sessionId` | string | UUID v4 | Session ID |
|
|
377
|
+
| `sessionSign` | string | 16..128 | MD5(append(session_id, secret_key)) |
|
|
378
|
+
| `deviceId` | string | ≤ 125 | Device unique ID |
|
|
379
|
+
| `platform` | string | - | Android, Ios, WebPC, WebMobile, SmartTV, AndroidTV |
|
|
380
|
+
| `deviceModel` | string | ≤ 125 | Model thiết bị |
|
|
381
|
+
| `deviceBrand` | string | ≤ 125 | Hãng thiết bị |
|
|
382
|
+
| `events` | array | - | Mảng events (không rỗng) |
|
|
531
383
|
|
|
532
|
-
|
|
384
|
+
### TrackingConfig (Optional Fields)
|
|
533
385
|
|
|
534
|
-
|
|
386
|
+
| Field | Type | Giới hạn | Mô tả |
|
|
387
|
+
| ----------------- | ------- | -------- | ------------------ |
|
|
388
|
+
| `adId` | string | ≤ 125 | GAID/IDFA |
|
|
389
|
+
| `deviceOsVersion` | string | ≤ 50 | VD: "14", "17.6" |
|
|
390
|
+
| `sdkVersion` | string | ≤ 50 | Phiên bản SDK |
|
|
391
|
+
| `debug` | boolean | - | Bật/tắt debug logs |
|
|
535
392
|
|
|
536
|
-
|
|
393
|
+
> **Lưu ý**: `ip_address` và `carrier_net` KHÔNG cần gửi. Server tự lấy từ header.
|
|
537
394
|
|
|
538
395
|
### Event Object Format
|
|
539
396
|
|
|
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 |
|
|
397
|
+
| Field | Type | Bắt buộc | Mô tả |
|
|
398
|
+
| -------------- | ------ | -------- | --------------------- |
|
|
399
|
+
| `user_id` | bigint | ✅ | -1 nếu chưa đăng nhập |
|
|
400
|
+
| `event_name` | string | ✅ | Tên event (≤ 125) |
|
|
401
|
+
| `event_time` | int | ✅ | Unix seconds |
|
|
402
|
+
| `event_params` | string | ❌ | JSON string (≤ 1024) |
|
|
603
403
|
|
|
604
404
|
---
|
|
605
405
|
|
|
606
|
-
##
|
|
406
|
+
## Publish
|
|
607
407
|
|
|
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
|
-
});
|
|
408
|
+
```bash
|
|
409
|
+
npm version patch
|
|
410
|
+
npm publish
|
|
619
411
|
```
|