@powerit/cms-tracker 1.0.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 +382 -0
- package/dist/index.d.ts +486 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# @powerit/cms-tracker
|
|
2
|
+
|
|
3
|
+
Session recording plugin for PowerIT CMS Client using [rrweb](https://github.com/rrweb-io/rrweb).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Session recording with rrweb for pixel-perfect replay
|
|
8
|
+
- Privacy-first design with comprehensive masking options
|
|
9
|
+
- GDPR-friendly CSS class-based exclusions
|
|
10
|
+
- Event batching and gzip compression
|
|
11
|
+
- Automatic session management
|
|
12
|
+
- Integration with @powerit/cms-analytics
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @powerit/cms-tracker
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Setup
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import { createClient } from '@powerit/cms-client';
|
|
26
|
+
import { trackerPlugin } from '@powerit/cms-tracker';
|
|
27
|
+
|
|
28
|
+
const client = createClient({
|
|
29
|
+
baseUrl: 'https://cms.example.com',
|
|
30
|
+
apiKey: 'your-api-key'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Add tracker plugin
|
|
34
|
+
client.use(trackerPlugin, {
|
|
35
|
+
privacy: {
|
|
36
|
+
maskAllInputs: true
|
|
37
|
+
},
|
|
38
|
+
compress: true
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Initialize and start recording
|
|
42
|
+
await client.tracker.init();
|
|
43
|
+
client.startRecording();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### With Analytics Integration
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
import { createClient } from '@powerit/cms-client';
|
|
50
|
+
import { analyticsPlugin } from '@powerit/cms-analytics';
|
|
51
|
+
import { trackerPlugin } from '@powerit/cms-tracker';
|
|
52
|
+
|
|
53
|
+
const client = createClient({
|
|
54
|
+
baseUrl: 'https://cms.example.com',
|
|
55
|
+
apiKey: 'your-api-key'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Add both plugins - tracker will link to analytics session
|
|
59
|
+
client.use(analyticsPlugin, { transport: 'grpc' });
|
|
60
|
+
client.use(trackerPlugin, { compress: true });
|
|
61
|
+
|
|
62
|
+
// Initialize both
|
|
63
|
+
await client.analytics.init();
|
|
64
|
+
await client.tracker.init();
|
|
65
|
+
|
|
66
|
+
// Track page and start recording
|
|
67
|
+
await client.trackPageView();
|
|
68
|
+
client.startRecording();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Custom Events
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
// Add custom event to recording
|
|
75
|
+
client.addCustomEvent('button_click', {
|
|
76
|
+
buttonId: 'cta-hero',
|
|
77
|
+
label: 'Sign Up'
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Identify user (after login)
|
|
81
|
+
client.identifyUser('user_123', {
|
|
82
|
+
plan: 'premium',
|
|
83
|
+
company: 'Acme Inc'
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Take manual snapshot
|
|
87
|
+
client.takeSnapshot();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Recording Controls
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// Start recording
|
|
94
|
+
client.startRecording();
|
|
95
|
+
|
|
96
|
+
// Pause (keeps session active)
|
|
97
|
+
client.pauseRecording();
|
|
98
|
+
|
|
99
|
+
// Resume
|
|
100
|
+
client.resumeRecording();
|
|
101
|
+
|
|
102
|
+
// Stop and flush
|
|
103
|
+
await client.stopRecording();
|
|
104
|
+
|
|
105
|
+
// Check status
|
|
106
|
+
client.tracker.isRecording(); // true/false
|
|
107
|
+
client.tracker.isEnabled(); // true/false
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Configuration
|
|
111
|
+
|
|
112
|
+
### Full Configuration Example
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
client.use(trackerPlugin, {
|
|
116
|
+
// Transport settings
|
|
117
|
+
transport: 'http', // 'http' or 'grpc'
|
|
118
|
+
transportUrl: null, // Custom URL (defaults to client baseUrl)
|
|
119
|
+
|
|
120
|
+
// Batching & compression
|
|
121
|
+
batchSize: 50, // Events per batch
|
|
122
|
+
flushInterval: 5000, // Auto-flush interval (ms)
|
|
123
|
+
maxQueueSize: 500, // Force flush threshold
|
|
124
|
+
compress: true, // Gzip compression
|
|
125
|
+
|
|
126
|
+
// Checkpoints
|
|
127
|
+
checkoutEveryNth: 200, // Full snapshot every N events
|
|
128
|
+
checkoutEveryNms: 300000, // Full snapshot every 5 minutes
|
|
129
|
+
|
|
130
|
+
// Session
|
|
131
|
+
sessionTimeout: 1800000, // 30 minutes
|
|
132
|
+
storageKey: 'powerit_tracker',
|
|
133
|
+
|
|
134
|
+
// Logging
|
|
135
|
+
logger: true, // Enable console logging
|
|
136
|
+
|
|
137
|
+
// Error handling
|
|
138
|
+
onError: (error) => console.error('Tracker error:', error),
|
|
139
|
+
|
|
140
|
+
// Privacy settings (see below)
|
|
141
|
+
privacy: { ... },
|
|
142
|
+
|
|
143
|
+
// Sampling settings (see below)
|
|
144
|
+
sampling: { ... },
|
|
145
|
+
|
|
146
|
+
// Recording settings (see below)
|
|
147
|
+
recording: { ... }
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Privacy Configuration
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
{
|
|
155
|
+
privacy: {
|
|
156
|
+
// Do Not Track
|
|
157
|
+
respectDoNotTrack: true,
|
|
158
|
+
|
|
159
|
+
// CSS classes for privacy control
|
|
160
|
+
blockClass: 'rr-block', // Element replaced with placeholder
|
|
161
|
+
ignoreClass: 'rr-ignore', // Input events not recorded
|
|
162
|
+
maskTextClass: 'rr-mask', // Text content masked
|
|
163
|
+
|
|
164
|
+
// CSS selectors for additional control
|
|
165
|
+
blockSelector: '.private-section',
|
|
166
|
+
ignoreSelector: '[data-no-track]',
|
|
167
|
+
maskTextSelector: '.sensitive-data',
|
|
168
|
+
|
|
169
|
+
// Input masking (privacy-first defaults)
|
|
170
|
+
maskAllInputs: true,
|
|
171
|
+
maskInputOptions: {
|
|
172
|
+
password: true,
|
|
173
|
+
email: true,
|
|
174
|
+
tel: true,
|
|
175
|
+
creditCard: true,
|
|
176
|
+
text: false,
|
|
177
|
+
textarea: false,
|
|
178
|
+
select: false
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// Custom masking functions
|
|
182
|
+
maskInputFn: (text, element) => '*'.repeat(text.length),
|
|
183
|
+
maskTextFn: (text, element) => text.replace(/./g, '*'),
|
|
184
|
+
|
|
185
|
+
// Page filters
|
|
186
|
+
blockedPages: [
|
|
187
|
+
'/admin',
|
|
188
|
+
'/checkout',
|
|
189
|
+
/^\/account/ // Regex pattern
|
|
190
|
+
],
|
|
191
|
+
allowedPages: [] // If set, only these pages are recorded
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Sampling Configuration
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
{
|
|
200
|
+
sampling: {
|
|
201
|
+
enabled: true,
|
|
202
|
+
sessionRate: 10, // Record 10% of sessions
|
|
203
|
+
mousemove: 50, // Events per second
|
|
204
|
+
mouseInteraction: true,
|
|
205
|
+
scroll: 10, // Events per second
|
|
206
|
+
media: true,
|
|
207
|
+
input: 'last' // Only capture final value
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Recording Configuration
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
{
|
|
216
|
+
recording: {
|
|
217
|
+
recordCanvas: false,
|
|
218
|
+
recordCrossOriginIframes: false,
|
|
219
|
+
inlineStylesheet: true,
|
|
220
|
+
inlineImages: false,
|
|
221
|
+
collectFonts: false,
|
|
222
|
+
slimDOMOptions: {
|
|
223
|
+
script: true,
|
|
224
|
+
comment: true,
|
|
225
|
+
headFavicon: true,
|
|
226
|
+
headWhitespace: true,
|
|
227
|
+
headMetaDescKeywords: true,
|
|
228
|
+
headMetaSocial: true,
|
|
229
|
+
headMetaRobots: true,
|
|
230
|
+
headMetaHttpEquiv: true,
|
|
231
|
+
headMetaAuthorship: true,
|
|
232
|
+
headMetaVerification: true
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Privacy Controls
|
|
239
|
+
|
|
240
|
+
### CSS Classes
|
|
241
|
+
|
|
242
|
+
Add these classes to your HTML to control recording:
|
|
243
|
+
|
|
244
|
+
| Class | Effect |
|
|
245
|
+
|-------|--------|
|
|
246
|
+
| `.rr-block` | Element replaced with a placeholder (same dimensions) |
|
|
247
|
+
| `.rr-ignore` | Input events not recorded |
|
|
248
|
+
| `.rr-mask` | Text content masked with `*` characters |
|
|
249
|
+
|
|
250
|
+
### HTML Examples
|
|
251
|
+
|
|
252
|
+
```html
|
|
253
|
+
<!-- Block entire element from recording -->
|
|
254
|
+
<div class="rr-block">
|
|
255
|
+
<p>This content will be replaced with a placeholder</p>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<!-- Ignore input events but show element -->
|
|
259
|
+
<input class="rr-ignore" type="text" name="search" />
|
|
260
|
+
|
|
261
|
+
<!-- Mask text content -->
|
|
262
|
+
<span class="rr-mask">user@email.com</span>
|
|
263
|
+
|
|
264
|
+
<!-- Custom data attributes -->
|
|
265
|
+
<div data-sensitive>Credit card ending in 4242</div>
|
|
266
|
+
<section data-no-record>Private notes</section>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Auto-Blocked Elements
|
|
270
|
+
|
|
271
|
+
The following selectors are automatically blocked/masked:
|
|
272
|
+
|
|
273
|
+
- `input[type="password"]`
|
|
274
|
+
- `input[name*="credit"]`
|
|
275
|
+
- `input[name*="card"]`
|
|
276
|
+
- `input[autocomplete="cc-number"]`
|
|
277
|
+
- `[data-sensitive]`
|
|
278
|
+
- `[data-private]`
|
|
279
|
+
- `[data-no-record]`
|
|
280
|
+
|
|
281
|
+
## Session Management
|
|
282
|
+
|
|
283
|
+
Sessions are automatically managed with:
|
|
284
|
+
|
|
285
|
+
- **Session ID**: Stored in `sessionStorage` (cleared on tab close)
|
|
286
|
+
- **Visitor ID**: Stored in `localStorage` (persistent across sessions)
|
|
287
|
+
- **Session timeout**: 30 minutes of inactivity (configurable)
|
|
288
|
+
|
|
289
|
+
Access session info:
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
const session = client.tracker.getSession();
|
|
293
|
+
// {
|
|
294
|
+
// sessionId: 'abc-123',
|
|
295
|
+
// visitorId: 'xyz-789',
|
|
296
|
+
// startedAt: 1703123456789,
|
|
297
|
+
// lastActivityAt: 1703123556789,
|
|
298
|
+
// eventCount: 42,
|
|
299
|
+
// linkedToAnalytics: true
|
|
300
|
+
// }
|
|
301
|
+
|
|
302
|
+
client.tracker.getSessionId(); // 'abc-123'
|
|
303
|
+
client.tracker.getVisitorId(); // 'xyz-789'
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Compression
|
|
307
|
+
|
|
308
|
+
Events are compressed using the browser's `CompressionStream` API (gzip) when available. This typically reduces payload size by 70-90%.
|
|
309
|
+
|
|
310
|
+
```javascript
|
|
311
|
+
import { compressEvents, decompressEvents, estimateCompression } from '@powerit/cms-tracker';
|
|
312
|
+
|
|
313
|
+
// Compress events manually
|
|
314
|
+
const compressed = await compressEvents(events);
|
|
315
|
+
// { type: 'gzip', data: 'base64...', originalSize: 10000, compressedSize: 2000 }
|
|
316
|
+
|
|
317
|
+
// Decompress for debugging
|
|
318
|
+
const events = await decompressEvents(compressed);
|
|
319
|
+
|
|
320
|
+
// Estimate compression ratio
|
|
321
|
+
const stats = await estimateCompression(events);
|
|
322
|
+
// { ratio: '5.00', savings: '80.0%', type: 'gzip' }
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## API Reference
|
|
326
|
+
|
|
327
|
+
### SessionRecorder
|
|
328
|
+
|
|
329
|
+
| Method | Description |
|
|
330
|
+
|--------|-------------|
|
|
331
|
+
| `init()` | Initialize the recorder |
|
|
332
|
+
| `start()` | Start recording |
|
|
333
|
+
| `pause()` | Pause recording |
|
|
334
|
+
| `resume()` | Resume recording |
|
|
335
|
+
| `stop()` | Stop and flush |
|
|
336
|
+
| `isRecording()` | Check if recording |
|
|
337
|
+
| `isEnabled()` | Check if enabled |
|
|
338
|
+
| `getSession()` | Get session info |
|
|
339
|
+
| `flush()` | Flush pending events |
|
|
340
|
+
| `addCustomEvent(tag, payload)` | Add custom event |
|
|
341
|
+
| `identify(userId, traits)` | Identify user |
|
|
342
|
+
| `takeSnapshot()` | Take full snapshot |
|
|
343
|
+
| `updatePrivacy(config)` | Update privacy settings |
|
|
344
|
+
| `enable()` | Enable recording |
|
|
345
|
+
| `disable()` | Disable recording |
|
|
346
|
+
| `destroy()` | Cleanup |
|
|
347
|
+
|
|
348
|
+
### Client Methods (via plugin)
|
|
349
|
+
|
|
350
|
+
| Method | Description |
|
|
351
|
+
|--------|-------------|
|
|
352
|
+
| `client.tracker` | Access recorder instance |
|
|
353
|
+
| `client.startRecording()` | Start recording |
|
|
354
|
+
| `client.stopRecording()` | Stop recording |
|
|
355
|
+
| `client.pauseRecording()` | Pause recording |
|
|
356
|
+
| `client.resumeRecording()` | Resume recording |
|
|
357
|
+
| `client.addCustomEvent(tag, payload)` | Add custom event |
|
|
358
|
+
| `client.identifyUser(userId, traits)` | Identify user |
|
|
359
|
+
| `client.takeSnapshot()` | Take snapshot |
|
|
360
|
+
|
|
361
|
+
## Backend Integration
|
|
362
|
+
|
|
363
|
+
The tracker sends events to `/api/public/tracker/events`:
|
|
364
|
+
|
|
365
|
+
```json
|
|
366
|
+
POST /api/public/tracker/events
|
|
367
|
+
{
|
|
368
|
+
"session_id": "abc-123",
|
|
369
|
+
"visitor_id": "xyz-789",
|
|
370
|
+
"events": {
|
|
371
|
+
"type": "gzip",
|
|
372
|
+
"data": "base64-encoded-gzip-data"
|
|
373
|
+
},
|
|
374
|
+
"event_count": 50,
|
|
375
|
+
"timestamp": 1703123456789,
|
|
376
|
+
"is_exit": false
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## License
|
|
381
|
+
|
|
382
|
+
MIT
|