@tracelog/lib 0.8.3 → 0.10.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 +188 -14
- package/dist/browser/tracelog.esm.js +876 -793
- package/dist/browser/tracelog.esm.js.map +1 -1
- package/dist/browser/tracelog.js +2 -2
- package/dist/browser/tracelog.js.map +1 -1
- package/dist/cjs/api.js +0 -2
- package/dist/cjs/api.js.map +1 -1
- package/dist/cjs/constants/config.constants.d.ts +3 -0
- package/dist/cjs/constants/config.constants.d.ts.map +1 -1
- package/dist/cjs/constants/config.constants.js +21 -2
- package/dist/cjs/constants/config.constants.js.map +1 -1
- package/dist/cjs/constants/error.constants.d.ts +1 -1
- package/dist/cjs/constants/error.constants.d.ts.map +1 -1
- package/dist/cjs/constants/error.constants.js +1 -1
- package/dist/cjs/constants/error.constants.js.map +1 -1
- package/dist/cjs/handlers/click.handler.d.ts +2 -0
- package/dist/cjs/handlers/click.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/click.handler.js +27 -5
- package/dist/cjs/handlers/click.handler.js.map +1 -1
- package/dist/cjs/handlers/error.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/error.handler.js +1 -5
- package/dist/cjs/handlers/error.handler.js.map +1 -1
- package/dist/cjs/handlers/performance.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/performance.handler.js +0 -6
- package/dist/cjs/handlers/performance.handler.js.map +1 -1
- package/dist/cjs/handlers/scroll.handler.d.ts +9 -2
- package/dist/cjs/handlers/scroll.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/scroll.handler.js +133 -35
- package/dist/cjs/handlers/scroll.handler.js.map +1 -1
- package/dist/cjs/managers/event.manager.d.ts.map +1 -1
- package/dist/cjs/managers/event.manager.js +0 -14
- package/dist/cjs/managers/event.manager.js.map +1 -1
- package/dist/cjs/managers/sender.manager.d.ts.map +1 -1
- package/dist/cjs/managers/sender.manager.js +1 -15
- package/dist/cjs/managers/sender.manager.js.map +1 -1
- package/dist/cjs/types/config.types.d.ts +4 -4
- package/dist/cjs/types/config.types.d.ts.map +1 -1
- package/dist/cjs/types/event.types.d.ts +18 -0
- package/dist/cjs/types/event.types.d.ts.map +1 -1
- package/dist/cjs/types/event.types.js +9 -0
- package/dist/cjs/types/event.types.js.map +1 -1
- package/dist/cjs/utils/network/url.utils.d.ts +2 -1
- package/dist/cjs/utils/network/url.utils.d.ts.map +1 -1
- package/dist/cjs/utils/network/url.utils.js +6 -2
- package/dist/cjs/utils/network/url.utils.js.map +1 -1
- package/dist/cjs/utils/validations/config-validations.utils.d.ts.map +1 -1
- package/dist/cjs/utils/validations/config-validations.utils.js +15 -77
- package/dist/cjs/utils/validations/config-validations.utils.js.map +1 -1
- package/dist/esm/api.js +0 -2
- package/dist/esm/api.js.map +1 -1
- package/dist/esm/constants/config.constants.d.ts +3 -0
- package/dist/esm/constants/config.constants.d.ts.map +1 -1
- package/dist/esm/constants/config.constants.js +19 -0
- package/dist/esm/constants/config.constants.js.map +1 -1
- package/dist/esm/constants/error.constants.d.ts +1 -1
- package/dist/esm/constants/error.constants.d.ts.map +1 -1
- package/dist/esm/constants/error.constants.js +1 -1
- package/dist/esm/constants/error.constants.js.map +1 -1
- package/dist/esm/handlers/click.handler.d.ts +2 -0
- package/dist/esm/handlers/click.handler.d.ts.map +1 -1
- package/dist/esm/handlers/click.handler.js +28 -6
- package/dist/esm/handlers/click.handler.js.map +1 -1
- package/dist/esm/handlers/error.handler.d.ts.map +1 -1
- package/dist/esm/handlers/error.handler.js +2 -6
- package/dist/esm/handlers/error.handler.js.map +1 -1
- package/dist/esm/handlers/performance.handler.d.ts.map +1 -1
- package/dist/esm/handlers/performance.handler.js +0 -6
- package/dist/esm/handlers/performance.handler.js.map +1 -1
- package/dist/esm/handlers/scroll.handler.d.ts +9 -2
- package/dist/esm/handlers/scroll.handler.d.ts.map +1 -1
- package/dist/esm/handlers/scroll.handler.js +133 -35
- package/dist/esm/handlers/scroll.handler.js.map +1 -1
- package/dist/esm/managers/event.manager.d.ts.map +1 -1
- package/dist/esm/managers/event.manager.js +0 -14
- package/dist/esm/managers/event.manager.js.map +1 -1
- package/dist/esm/managers/sender.manager.d.ts.map +1 -1
- package/dist/esm/managers/sender.manager.js +1 -15
- package/dist/esm/managers/sender.manager.js.map +1 -1
- package/dist/esm/types/config.types.d.ts +4 -4
- package/dist/esm/types/config.types.d.ts.map +1 -1
- package/dist/esm/types/event.types.d.ts +18 -0
- package/dist/esm/types/event.types.d.ts.map +1 -1
- package/dist/esm/types/event.types.js +7 -0
- package/dist/esm/types/event.types.js.map +1 -1
- package/dist/esm/utils/network/url.utils.d.ts +2 -1
- package/dist/esm/utils/network/url.utils.d.ts.map +1 -1
- package/dist/esm/utils/network/url.utils.js +6 -2
- package/dist/esm/utils/network/url.utils.js.map +1 -1
- package/dist/esm/utils/validations/config-validations.utils.d.ts.map +1 -1
- package/dist/esm/utils/validations/config-validations.utils.js +15 -77
- package/dist/esm/utils/validations/config-validations.utils.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,12 +5,15 @@ A lightweight TypeScript library for web analytics and user behavior tracking. A
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Zero-config tracking** - Automatically captures clicks, scrolls, page navigation, and web vitals out of the box.
|
|
8
|
-
- **Cross-tab session management** - Maintains consistent user sessions across multiple browser tabs with automatic recovery.
|
|
8
|
+
- **Cross-tab session management** - Maintains consistent user sessions across multiple browser tabs with BroadcastChannel API and automatic localStorage recovery.
|
|
9
9
|
- **Client-only architecture** - Fully autonomous with optional backend integrations (TraceLog SaaS, custom API, Google Analytics).
|
|
10
|
-
- **Privacy-first** - Built-in PII sanitization and client-side sampling controls.
|
|
10
|
+
- **Privacy-first** - Built-in PII sanitization (emails, phone numbers, credit cards, API keys) and client-side sampling controls.
|
|
11
11
|
- **Framework agnostic** - Works with vanilla JS, React, Vue, Angular, or any web application.
|
|
12
12
|
- **Lightweight** - Only one dependency (`web-vitals`) with dual ESM/CJS support.
|
|
13
13
|
- **Event-driven** - Real-time event subscription with `on()` and `off()` methods for custom integrations.
|
|
14
|
+
- **Rate limiting** - Client-side rate limiting (200 events/second) with exemptions for critical events (SESSION_START/END).
|
|
15
|
+
- **Event recovery** - Automatic recovery of persisted events from localStorage after crashes or network failures.
|
|
16
|
+
- **Smart filtering** - Threshold-based web vitals reporting, deduplication (10px click precision), and intelligent queue management.
|
|
14
17
|
|
|
15
18
|
## Installation
|
|
16
19
|
|
|
@@ -140,18 +143,23 @@ await tracelog.init({
|
|
|
140
143
|
- `destroy(): Promise<void>` - Clean up and remove listeners
|
|
141
144
|
|
|
142
145
|
**Config (all optional):**
|
|
143
|
-
- `sessionTimeout`: Session timeout in ms (default: 900000)
|
|
146
|
+
- `sessionTimeout`: Session timeout in ms (default: 900000 / 15 minutes, range: 30s - 24 hours)
|
|
144
147
|
- `globalMetadata`: Metadata attached to all events
|
|
145
148
|
- `samplingRate`: Event sampling rate 0-1 (default: 1.0)
|
|
146
|
-
- `errorSampling`: Error sampling rate 0-1 (default: 1.0)
|
|
149
|
+
- `errorSampling`: Error sampling rate 0-1 (default: 1.0 / 100%)
|
|
147
150
|
- `sensitiveQueryParams`: Query params to remove from URLs
|
|
148
|
-
- `
|
|
151
|
+
- `primaryScrollSelector`: Override automatic primary scroll container detection (e.g., `.mat-sidenav-content`, `window`)
|
|
149
152
|
- `integrations`:
|
|
150
153
|
- `tracelog.projectId`: TraceLog SaaS
|
|
151
154
|
- `custom.collectApiUrl`: Custom backend
|
|
152
155
|
- `custom.allowHttp`: Enable HTTP for testing
|
|
153
156
|
- `googleAnalytics.measurementId`: GA4
|
|
154
157
|
|
|
158
|
+
**📚 For detailed configuration and implementation, see:**
|
|
159
|
+
- [Handlers Documentation](./src/handlers/README.md) - Event capture logic
|
|
160
|
+
- [Managers Documentation](./src/managers/README.md) - Core components
|
|
161
|
+
- [Listeners Documentation](./src/listeners/README.md) - Activity tracking
|
|
162
|
+
|
|
155
163
|
## Event Data Structure
|
|
156
164
|
|
|
157
165
|
Each event contains a base structure with type-specific data:
|
|
@@ -185,20 +193,40 @@ Each event contains a base structure with type-specific data:
|
|
|
185
193
|
- **`SCROLL`**: Scroll engagement
|
|
186
194
|
- `scroll_data.depth`: Scroll depth percentage (0-100)
|
|
187
195
|
- `scroll_data.direction`: Scroll direction (up/down)
|
|
196
|
+
- `scroll_data.container_selector`: CSS selector identifying scroll container (e.g., `window`, `.mat-sidenav-content`, `#main`)
|
|
197
|
+
- `scroll_data.is_primary`: Whether this is the main scroll container (true for primary content, false for sidebars/modals)
|
|
198
|
+
- `scroll_data.velocity`: Scroll speed in pixels per second (for engagement analysis)
|
|
199
|
+
- `scroll_data.max_depth_reached`: Maximum scroll depth reached in current session (0-100)
|
|
200
|
+
|
|
201
|
+
### Scroll Container Detection
|
|
202
|
+
|
|
203
|
+
**Primary Container Logic**:
|
|
204
|
+
- If `window` is scrollable → `window` is primary (`is_primary: true`)
|
|
205
|
+
- If `window` NOT scrollable → First detected container is primary (e.g., `.mat-sidenav-content` in Angular Material)
|
|
206
|
+
- All other containers are secondary (`is_primary: false`)
|
|
207
|
+
|
|
208
|
+
**Important Notes**:
|
|
209
|
+
- `is_primary` is calculated ONCE when container is detected
|
|
210
|
+
- Does not re-calculate if layout changes dynamically during session
|
|
211
|
+
- Pages without scroll: Window is marked primary but generates no events (scroll impossible)
|
|
212
|
+
- Historical events maintain their original `is_primary` value for consistency
|
|
188
213
|
|
|
189
|
-
- **`SESSION_START`**: Session initialization
|
|
190
|
-
-
|
|
214
|
+
- **`SESSION_START`**: Session initialization (cross-tab synchronized)
|
|
215
|
+
- Session ID format: `{timestamp}-{9-char-base36}` (e.g., `1728488234567-kx9f2m1bq`)
|
|
216
|
+
- See [SessionManager docs](./src/managers/README.md#sessionmanager) for cross-tab sync details
|
|
191
217
|
|
|
192
|
-
- **`SESSION_END`**: Session termination
|
|
193
|
-
- `session_end_reason`:
|
|
218
|
+
- **`SESSION_END`**: Session termination (synchronous flush before page unload)
|
|
219
|
+
- `session_end_reason`: `inactivity`, `page_unload`, `manual_stop`, `orphaned_cleanup`, or `tab_closed`
|
|
194
220
|
|
|
195
221
|
- **`CUSTOM`**: Business-specific events
|
|
196
222
|
- `custom_event.name`: Event name
|
|
197
223
|
- `custom_event.metadata`: Custom data (any JSON-serializable value)
|
|
198
224
|
|
|
199
|
-
- **`WEB_VITALS`**: Performance metrics
|
|
225
|
+
- **`WEB_VITALS`**: Performance metrics (only sent when exceeding quality thresholds)
|
|
200
226
|
- `web_vitals.type`: Metric type (LCP, CLS, INP, FCP, TTFB, LONG_TASK)
|
|
201
|
-
- `web_vitals.value`: Metric value in milliseconds
|
|
227
|
+
- `web_vitals.value`: Metric value in milliseconds or unitless (CLS)
|
|
228
|
+
- **Thresholds**: LCP >4000ms, FCP >1800ms, CLS >0.25, INP >200ms, TTFB >800ms, LONG_TASK >50ms
|
|
229
|
+
- See [PerformanceHandler docs](./src/handlers/README.md#performancehandler) for details
|
|
202
230
|
|
|
203
231
|
- **`ERROR`**: JavaScript errors
|
|
204
232
|
- `error_data.type`: Error type (js_error, promise_rejection)
|
|
@@ -218,6 +246,67 @@ await tracelog.init();
|
|
|
218
246
|
|
|
219
247
|
**Note**: Listeners are buffered if registered before `init()`, ensuring you don't miss initial events.
|
|
220
248
|
|
|
249
|
+
**Filter scroll events by primary container:**
|
|
250
|
+
```typescript
|
|
251
|
+
tracelog.on('event', (event) => {
|
|
252
|
+
if (event.type === 'scroll') {
|
|
253
|
+
const { is_primary, container_selector, depth, velocity } = event.scroll_data;
|
|
254
|
+
|
|
255
|
+
if (is_primary) {
|
|
256
|
+
// Track main content engagement
|
|
257
|
+
console.log(`Primary scroll (${container_selector}): ${depth}%`);
|
|
258
|
+
|
|
259
|
+
// Identify engaged users (slow scroll = reading)
|
|
260
|
+
if (velocity < 500 && depth > 50) {
|
|
261
|
+
console.log('User is reading deeply');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Identify bouncing users (fast scroll = scanning)
|
|
265
|
+
if (velocity > 2000) {
|
|
266
|
+
console.log('User is quickly scanning');
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
// Track auxiliary UI interaction
|
|
270
|
+
console.log(`Secondary scroll (${container_selector}): ${depth}%`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Analytics queries example:**
|
|
277
|
+
```typescript
|
|
278
|
+
// In your analytics backend
|
|
279
|
+
const primaryScrollEvents = events.filter(e =>
|
|
280
|
+
e.type === 'scroll' && e.scroll_data.is_primary
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const avgPrimaryDepth = primaryScrollEvents.reduce((sum, e) =>
|
|
284
|
+
sum + e.scroll_data.depth, 0
|
|
285
|
+
) / primaryScrollEvents.length;
|
|
286
|
+
|
|
287
|
+
console.log(`Average primary content depth: ${avgPrimaryDepth}%`);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**TypeScript type helpers:**
|
|
291
|
+
```typescript
|
|
292
|
+
import { tracelog, isPrimaryScrollEvent, isSecondaryScrollEvent, EmitterEvent } from '@tracelog/lib';
|
|
293
|
+
|
|
294
|
+
tracelog.on(EmitterEvent.EVENT, (event) => {
|
|
295
|
+
// Type guard provides type safety
|
|
296
|
+
if (isPrimaryScrollEvent(event)) {
|
|
297
|
+
// TypeScript knows event.scroll_data.is_primary === true
|
|
298
|
+
const depth = event.scroll_data.depth;
|
|
299
|
+
console.log(`Primary scroll depth: ${depth}%`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (isSecondaryScrollEvent(event)) {
|
|
303
|
+
// TypeScript knows event.scroll_data.is_primary === false
|
|
304
|
+
const selector = event.scroll_data.container_selector;
|
|
305
|
+
console.log(`Secondary UI scroll: ${selector}`);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
221
310
|
**Multiple integrations:**
|
|
222
311
|
```typescript
|
|
223
312
|
await tracelog.init({
|
|
@@ -233,6 +322,32 @@ await tracelog.init({
|
|
|
233
322
|
window.__traceLogDisabled = true;
|
|
234
323
|
```
|
|
235
324
|
|
|
325
|
+
### Manual Primary Container Selection
|
|
326
|
+
|
|
327
|
+
For edge cases requiring manual override of automatic primary container detection:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
await tracelog.init({
|
|
331
|
+
primaryScrollSelector: '#custom-content' // Override auto-detection
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// To mark window as primary:
|
|
335
|
+
await tracelog.init({
|
|
336
|
+
primaryScrollSelector: 'window'
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**When to use**: In 99% of cases, automatic detection is sufficient. Use manual selection only when:
|
|
341
|
+
- You need to override automatic detection for a specific business requirement
|
|
342
|
+
- Your UI has multiple main content areas and you want to prioritize one
|
|
343
|
+
|
|
344
|
+
**Important Notes:**
|
|
345
|
+
- `primaryScrollSelector` is applied during `init()` and affects all subsequently detected containers
|
|
346
|
+
- The selector is applied BEFORE automatic detection to ensure priority and avoid race conditions
|
|
347
|
+
- If you call `init()` multiple times, only the LAST `primaryScrollSelector` will be active
|
|
348
|
+
- To change primary container dynamically, call `destroy()` then `init()` with new selector
|
|
349
|
+
- Calling `init()` does NOT clear previously detected containers unless `destroy()` is called first
|
|
350
|
+
|
|
236
351
|
## Compatibility
|
|
237
352
|
|
|
238
353
|
- **Runtime**: Modern browsers (Chrome 60+, Firefox 55+, Safari 12+)
|
|
@@ -268,14 +383,18 @@ TraceLog uses a hybrid sendBeacon/fetch strategy with intelligent error handling
|
|
|
268
383
|
- **Permanent errors (4xx)**: Events are discarded immediately
|
|
269
384
|
- `400 Bad Request`, `403 Forbidden`, `404 Not Found` → No persistence, no retry
|
|
270
385
|
- Prevents infinite retry loops for configuration issues (e.g., excluded IPs, invalid projects)
|
|
386
|
+
- Throttled logging (1 log per status code per minute) to prevent console spam
|
|
271
387
|
|
|
272
388
|
- **Temporary errors (5xx, network failures)**: Events persist in localStorage
|
|
273
389
|
- `500`, `502`, `503`, `504` → Events saved for recovery on next page load
|
|
274
390
|
- Network failures → Events persist and recover automatically
|
|
275
|
-
- No automatic in-session retries to avoid performance impact
|
|
391
|
+
- **No automatic in-session retries** to avoid performance impact and battery drain
|
|
392
|
+
- Recovery attempted on next page load via `recoverPersistedEvents()`
|
|
276
393
|
|
|
277
394
|
- **Event expiry**: Persisted events expire after 2 hours to prevent stale data recovery
|
|
278
395
|
|
|
396
|
+
See [SenderManager docs](./src/managers/README.md#sendermanager) for complete error handling details.
|
|
397
|
+
|
|
279
398
|
### sendBeacon Limitations
|
|
280
399
|
|
|
281
400
|
When using `sendBeacon` (page unload scenarios):
|
|
@@ -286,11 +405,20 @@ When using `sendBeacon` (page unload scenarios):
|
|
|
286
405
|
|
|
287
406
|
## Troubleshooting
|
|
288
407
|
|
|
289
|
-
- **Session issues**: Check localStorage availability and session timeout
|
|
408
|
+
- **Session issues**: Check localStorage availability and session timeout. See [SessionManager docs](./src/managers/README.md#sessionmanager)
|
|
290
409
|
- **Memory usage**: Reduce `sessionTimeout`, lower `samplingRate`, call `destroy()` on cleanup
|
|
291
|
-
- **Events not sending**:
|
|
410
|
+
- **Events not sending**:
|
|
411
|
+
- Check browser console for `PermanentError` logs indicating 4xx errors
|
|
412
|
+
- Verify integration configuration (`projectId` or `collectApiUrl`)
|
|
413
|
+
- Check network tab for failed requests to `/collect` endpoint
|
|
414
|
+
- **Rate limiting**: If events are being dropped, check console for rate limit warnings (200 events/second max)
|
|
415
|
+
- **Scroll detection issues**: Use `primaryScrollSelector` to manually specify main content container
|
|
292
416
|
- **CI failures**: Verify Playwright installation and Node.js ≥20
|
|
293
417
|
|
|
418
|
+
**Detailed troubleshooting guides:**
|
|
419
|
+
- [Handlers troubleshooting](./src/handlers/README.md) - Event capture issues
|
|
420
|
+
- [Managers troubleshooting](./src/managers/README.md) - State, storage, and network issues
|
|
421
|
+
|
|
294
422
|
## Development & Contributing
|
|
295
423
|
|
|
296
424
|
### Development Setup
|
|
@@ -321,6 +449,52 @@ npm run test:unit # Unit tests
|
|
|
321
449
|
npm run test:e2e # E2E tests
|
|
322
450
|
```
|
|
323
451
|
|
|
452
|
+
## Security & Privacy
|
|
453
|
+
|
|
454
|
+
TraceLog is designed with **privacy-first** principles. Key security guarantees:
|
|
455
|
+
|
|
456
|
+
### ✅ What We Protect
|
|
457
|
+
|
|
458
|
+
- **Input Value Protection**: NEVER captures values from `<input>`, `<textarea>`, or `<select>` elements
|
|
459
|
+
- **PII Sanitization**: Automatically redacts emails, phone numbers, credit cards, and API keys from error messages and click text
|
|
460
|
+
- **Default URL Filtering**: Removes sensitive query parameters (`token`, `auth`, `key`, `session`, `password`, `api_key`, `secret`, etc.)
|
|
461
|
+
- **Client-Side Controls**: All validation, sampling, and deduplication happen in the browser
|
|
462
|
+
- **XSS Protection**: All metadata is sanitized against common XSS patterns
|
|
463
|
+
|
|
464
|
+
### 🛡️ Tools for You
|
|
465
|
+
|
|
466
|
+
- **`data-tlog-ignore` Attribute**: Exclude sensitive UI elements from tracking
|
|
467
|
+
```html
|
|
468
|
+
<!-- Payment form - completely ignored -->
|
|
469
|
+
<div data-tlog-ignore>
|
|
470
|
+
<input type="text" name="card_number">
|
|
471
|
+
<button>Pay Now</button>
|
|
472
|
+
</div>
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
- **Custom URL Parameters**: Extend default filtering with your own sensitive params
|
|
476
|
+
```typescript
|
|
477
|
+
await tracelog.init({
|
|
478
|
+
sensitiveQueryParams: ['affiliate_id', 'promo_code'] // Merged with defaults
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
- **Conditional Sampling**: Adjust tracking based on user consent level
|
|
483
|
+
```typescript
|
|
484
|
+
const samplingRate = userConsent === 'full' ? 1.0 : 0.1;
|
|
485
|
+
await tracelog.init({ samplingRate });
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### 📋 Your Responsibilities
|
|
489
|
+
|
|
490
|
+
- **GDPR Consent**: Initialize TraceLog ONLY after user consent, call `destroy()` on revoke
|
|
491
|
+
- **Custom Event Data**: Sanitize PII before sending via `tracelog.event()`
|
|
492
|
+
- **Sensitive Elements**: Mark admin/payment UI with `data-tlog-ignore`
|
|
493
|
+
|
|
494
|
+
**📚 Read the full security guide:** [SECURITY.md](./SECURITY.md)
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
324
498
|
## License
|
|
325
499
|
|
|
326
500
|
MIT © TraceLog. See [LICENSE](LICENSE) file for details.
|