@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 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