@tracelog/lib 0.9.0 → 0.11.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.
Files changed (116) hide show
  1. package/README.md +128 -361
  2. package/dist/browser/tracelog.esm.js +1371 -937
  3. package/dist/browser/tracelog.esm.js.map +1 -1
  4. package/dist/browser/tracelog.js +2 -2
  5. package/dist/browser/tracelog.js.map +1 -1
  6. package/dist/cjs/app.d.ts +2 -0
  7. package/dist/cjs/app.d.ts.map +1 -1
  8. package/dist/cjs/app.js +5 -0
  9. package/dist/cjs/app.js.map +1 -1
  10. package/dist/cjs/constants/config.constants.d.ts +27 -1
  11. package/dist/cjs/constants/config.constants.d.ts.map +1 -1
  12. package/dist/cjs/constants/config.constants.js +47 -3
  13. package/dist/cjs/constants/config.constants.js.map +1 -1
  14. package/dist/cjs/constants/error.constants.d.ts +15 -0
  15. package/dist/cjs/constants/error.constants.d.ts.map +1 -1
  16. package/dist/cjs/constants/error.constants.js +19 -1
  17. package/dist/cjs/constants/error.constants.js.map +1 -1
  18. package/dist/cjs/handlers/click.handler.d.ts +17 -0
  19. package/dist/cjs/handlers/click.handler.d.ts.map +1 -1
  20. package/dist/cjs/handlers/click.handler.js +96 -5
  21. package/dist/cjs/handlers/click.handler.js.map +1 -1
  22. package/dist/cjs/handlers/error.handler.d.ts +7 -0
  23. package/dist/cjs/handlers/error.handler.d.ts.map +1 -1
  24. package/dist/cjs/handlers/error.handler.js +35 -0
  25. package/dist/cjs/handlers/error.handler.js.map +1 -1
  26. package/dist/cjs/handlers/page-view.handler.d.ts +1 -0
  27. package/dist/cjs/handlers/page-view.handler.d.ts.map +1 -1
  28. package/dist/cjs/handlers/page-view.handler.js +11 -0
  29. package/dist/cjs/handlers/page-view.handler.js.map +1 -1
  30. package/dist/cjs/handlers/performance.handler.js +5 -5
  31. package/dist/cjs/handlers/performance.handler.js.map +1 -1
  32. package/dist/cjs/handlers/viewport.handler.d.ts +44 -0
  33. package/dist/cjs/handlers/viewport.handler.d.ts.map +1 -0
  34. package/dist/cjs/handlers/viewport.handler.js +286 -0
  35. package/dist/cjs/handlers/viewport.handler.js.map +1 -0
  36. package/dist/cjs/managers/event.manager.d.ts +23 -3
  37. package/dist/cjs/managers/event.manager.d.ts.map +1 -1
  38. package/dist/cjs/managers/event.manager.js +166 -10
  39. package/dist/cjs/managers/event.manager.js.map +1 -1
  40. package/dist/cjs/managers/sender.manager.d.ts.map +1 -1
  41. package/dist/cjs/managers/sender.manager.js +12 -0
  42. package/dist/cjs/managers/sender.manager.js.map +1 -1
  43. package/dist/cjs/types/config.types.d.ts +9 -0
  44. package/dist/cjs/types/config.types.d.ts.map +1 -1
  45. package/dist/cjs/types/config.types.js.map +1 -1
  46. package/dist/cjs/types/event.types.d.ts +4 -1
  47. package/dist/cjs/types/event.types.d.ts.map +1 -1
  48. package/dist/cjs/types/event.types.js +1 -0
  49. package/dist/cjs/types/event.types.js.map +1 -1
  50. package/dist/cjs/types/viewport.types.d.ts +82 -0
  51. package/dist/cjs/types/viewport.types.d.ts.map +1 -0
  52. package/dist/cjs/types/viewport.types.js +3 -0
  53. package/dist/cjs/types/viewport.types.js.map +1 -0
  54. package/dist/cjs/utils/network/url.utils.d.ts +2 -1
  55. package/dist/cjs/utils/network/url.utils.d.ts.map +1 -1
  56. package/dist/cjs/utils/network/url.utils.js +6 -2
  57. package/dist/cjs/utils/network/url.utils.js.map +1 -1
  58. package/dist/cjs/utils/validations/config-validations.utils.d.ts.map +1 -1
  59. package/dist/cjs/utils/validations/config-validations.utils.js +91 -0
  60. package/dist/cjs/utils/validations/config-validations.utils.js.map +1 -1
  61. package/dist/esm/app.d.ts +2 -0
  62. package/dist/esm/app.d.ts.map +1 -1
  63. package/dist/esm/app.js +5 -0
  64. package/dist/esm/app.js.map +1 -1
  65. package/dist/esm/constants/config.constants.d.ts +27 -1
  66. package/dist/esm/constants/config.constants.d.ts.map +1 -1
  67. package/dist/esm/constants/config.constants.js +45 -1
  68. package/dist/esm/constants/config.constants.js.map +1 -1
  69. package/dist/esm/constants/error.constants.d.ts +15 -0
  70. package/dist/esm/constants/error.constants.d.ts.map +1 -1
  71. package/dist/esm/constants/error.constants.js +18 -0
  72. package/dist/esm/constants/error.constants.js.map +1 -1
  73. package/dist/esm/handlers/click.handler.d.ts +17 -0
  74. package/dist/esm/handlers/click.handler.d.ts.map +1 -1
  75. package/dist/esm/handlers/click.handler.js +97 -6
  76. package/dist/esm/handlers/click.handler.js.map +1 -1
  77. package/dist/esm/handlers/error.handler.d.ts +7 -0
  78. package/dist/esm/handlers/error.handler.d.ts.map +1 -1
  79. package/dist/esm/handlers/error.handler.js +36 -1
  80. package/dist/esm/handlers/error.handler.js.map +1 -1
  81. package/dist/esm/handlers/page-view.handler.d.ts +1 -0
  82. package/dist/esm/handlers/page-view.handler.d.ts.map +1 -1
  83. package/dist/esm/handlers/page-view.handler.js +11 -0
  84. package/dist/esm/handlers/page-view.handler.js.map +1 -1
  85. package/dist/esm/handlers/performance.handler.js +5 -5
  86. package/dist/esm/handlers/performance.handler.js.map +1 -1
  87. package/dist/esm/handlers/viewport.handler.d.ts +44 -0
  88. package/dist/esm/handlers/viewport.handler.d.ts.map +1 -0
  89. package/dist/esm/handlers/viewport.handler.js +282 -0
  90. package/dist/esm/handlers/viewport.handler.js.map +1 -0
  91. package/dist/esm/managers/event.manager.d.ts +23 -3
  92. package/dist/esm/managers/event.manager.d.ts.map +1 -1
  93. package/dist/esm/managers/event.manager.js +167 -11
  94. package/dist/esm/managers/event.manager.js.map +1 -1
  95. package/dist/esm/managers/sender.manager.d.ts.map +1 -1
  96. package/dist/esm/managers/sender.manager.js +13 -1
  97. package/dist/esm/managers/sender.manager.js.map +1 -1
  98. package/dist/esm/types/config.types.d.ts +9 -0
  99. package/dist/esm/types/config.types.d.ts.map +1 -1
  100. package/dist/esm/types/config.types.js.map +1 -1
  101. package/dist/esm/types/event.types.d.ts +4 -1
  102. package/dist/esm/types/event.types.d.ts.map +1 -1
  103. package/dist/esm/types/event.types.js +1 -0
  104. package/dist/esm/types/event.types.js.map +1 -1
  105. package/dist/esm/types/viewport.types.d.ts +82 -0
  106. package/dist/esm/types/viewport.types.d.ts.map +1 -0
  107. package/dist/esm/types/viewport.types.js +2 -0
  108. package/dist/esm/types/viewport.types.js.map +1 -0
  109. package/dist/esm/utils/network/url.utils.d.ts +2 -1
  110. package/dist/esm/utils/network/url.utils.d.ts.map +1 -1
  111. package/dist/esm/utils/network/url.utils.js +6 -2
  112. package/dist/esm/utils/network/url.utils.js.map +1 -1
  113. package/dist/esm/utils/validations/config-validations.utils.d.ts.map +1 -1
  114. package/dist/esm/utils/validations/config-validations.utils.js +92 -1
  115. package/dist/esm/utils/validations/config-validations.utils.js.map +1 -1
  116. package/package.json +1 -1
package/README.md CHANGED
@@ -1,35 +1,19 @@
1
- # TraceLog Library
1
+ # TraceLog
2
2
 
3
- A lightweight TypeScript library for web analytics and user behavior tracking. Automatically captures clicks, scrolls, page views, and performance metrics with cross-tab session management and privacy-first design.
3
+ Lightweight web analytics library for tracking user behavior. Works standalone or with optional backend integrations.
4
4
 
5
5
  ## Features
6
6
 
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 BroadcastChannel API and automatic localStorage recovery.
9
- - **Client-only architecture** - Fully autonomous with optional backend integrations (TraceLog SaaS, custom API, Google Analytics).
10
- - **Privacy-first** - Built-in PII sanitization (emails, phone numbers, credit cards, API keys) and client-side sampling controls.
11
- - **Framework agnostic** - Works with vanilla JS, React, Vue, Angular, or any web application.
12
- - **Lightweight** - Only one dependency (`web-vitals`) with dual ESM/CJS support.
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.
7
+ - **Zero-config** - Auto-captures clicks, scrolls, page views, sessions, and performance metrics
8
+ - **Standalone** - No backend required; optional integrations (TraceLog SaaS, custom API, GA4)
9
+ - **Privacy-first** - PII sanitization, client-side sampling, `data-tlog-ignore` attribute
10
+ - **Cross-tab sessions** - BroadcastChannel sync with localStorage recovery
11
+ - **Event-driven** - Subscribe via `on()`/`off()` for real-time events
12
+ - **Lightweight** - Single dependency (`web-vitals`), 15KB gzipped
17
13
 
18
14
  ## Installation
19
15
 
20
- **Prerequisites**: Modern browser with ES6+ support.
21
-
22
- ## 📦 Which File Should I Use?
23
-
24
- | Your Setup | File to Use | How to Use |
25
- |-----------|-------------|------------|
26
- | **npm/yarn** (React, Vue, Angular, etc.) | Automatic | `import { tracelog } from '@tracelog/lib'` |
27
- | **HTML + `<script>` tag** | `tracelog.js` (IIFE) | `<script src="...tracelog.js"></script>` then use `tracelog.init()` |
28
- | **HTML + `<script type="module">`** | `tracelog.esm.js` (ESM) | `import { tracelog } from '...tracelog.esm.js'` |
29
-
30
- ### Installation Methods
31
-
32
- #### 1. NPM/Yarn (Recommended for Modern Apps)
16
+ ### NPM (Recommended)
33
17
  ```bash
34
18
  npm install @tracelog/lib
35
19
  ```
@@ -37,422 +21,205 @@ npm install @tracelog/lib
37
21
  ```typescript
38
22
  import { tracelog } from '@tracelog/lib';
39
23
 
40
- // Standalone mode (no backend required)
41
- tracelog.init();
24
+ // Standalone mode (no backend)
25
+ await tracelog.init();
42
26
 
43
- // OR with TraceLog SaaS integration
44
- tracelog.init({
27
+ // With TraceLog SaaS
28
+ await tracelog.init({
45
29
  integrations: {
46
30
  tracelog: { projectId: 'your-project-id' }
47
31
  }
48
32
  });
49
-
50
- tracelog.event('user_action', { data: 'example' });
51
33
  ```
52
34
 
53
- **✅ Best for:** React, Vue, Angular, Next.js, Vite, webpack, or any bundler
54
-
55
- ---
56
-
57
- #### 2. CDN - IIFE (Maximum Compatibility)
35
+ ### CDN (Script Tag)
58
36
  ```html
59
37
  <script src="https://cdn.jsdelivr.net/npm/@tracelog/lib@latest/dist/browser/tracelog.js"></script>
60
38
  <script>
61
- // Standalone mode
62
39
  tracelog.init();
63
-
64
- // OR with TraceLog SaaS
65
- tracelog.init({
66
- integrations: {
67
- tracelog: { projectId: 'your-project-id' }
68
- }
69
- });
70
40
  </script>
71
41
  ```
72
42
 
73
- **✅ Best for:** WordPress, static HTML, CMS, legacy browsers, no build step
74
-
75
- ---
76
-
77
- #### 3. CDN - ES Module (Modern Only)
43
+ ### CDN (ES Module)
78
44
  ```html
79
45
  <script type="module">
80
46
  import { tracelog } from 'https://cdn.jsdelivr.net/npm/@tracelog/lib@latest/dist/browser/tracelog.esm.js';
81
-
82
- await tracelog.init(); // Standalone mode
83
- tracelog.event('page_view');
47
+ await tracelog.init();
84
48
  </script>
85
49
  ```
86
50
 
87
- **✅ Best for:** Modern browsers, no bundler, prefer native modules
88
- **⚠️ Note:** Won't work in IE11 or older browsers
89
-
90
- ## How It Works
91
-
92
- - **Standalone Mode** (no `integrations`): Events captured and emitted locally via `on('event')`. No network requests.
93
- - **With Backend** (`integrations.tracelog` or `integrations.custom`): Events sent to configured endpoint after client-side validation.
94
-
95
- All validation, sampling, and deduplication happen client-side. Enable QA mode with `?tlog_mode=qa` URL parameter.
96
-
97
- ## Usage
51
+ ## Quick Start
98
52
 
99
53
  ```typescript
100
- // Standalone mode
101
- await tracelog.init({
102
- sessionTimeout: 30 * 60 * 1000,
103
- samplingRate: 1.0
104
- });
105
-
106
- // With TraceLog SaaS
107
- await tracelog.init({
108
- integrations: {
109
- tracelog: { projectId: 'your-project-id' }
110
- }
111
- });
112
-
113
- // With custom backend
114
- await tracelog.init({
115
- integrations: {
116
- custom: { collectApiUrl: 'https://your-api.com/collect' }
117
- }
118
- });
54
+ // Basic initialization
55
+ await tracelog.init();
119
56
 
120
57
  // Custom events
121
58
  tracelog.event('product_viewed', {
122
59
  productId: 'abc-123',
123
- category: 'electronics',
124
60
  price: 299.99
125
61
  });
126
62
 
127
- // Privacy controls
128
- await tracelog.init({
129
- sensitiveQueryParams: ['token', 'session_id'],
130
- samplingRate: 0.5,
131
- errorSampling: 0.1
63
+ // Subscribe to events
64
+ tracelog.on('event', (event) => {
65
+ console.log(event.type, event);
132
66
  });
67
+
68
+ // Cleanup
69
+ await tracelog.destroy();
133
70
  ```
134
71
 
135
- ## API
136
-
137
- **Methods:**
138
- - `init(config?: Config): Promise<void>` - Initialize tracking
139
- - `event(name: string, metadata?: Record<string, MetadataType>): void` - Send custom event
140
- - `on(event: string, callback: Function): void` - Subscribe to events
141
- - `off(event: string, callback: Function): void` - Unsubscribe from events
142
- - `isInitialized(): boolean` - Check initialization status
143
- - `destroy(): Promise<void>` - Clean up and remove listeners
144
-
145
- **Config (all optional):**
146
- - `sessionTimeout`: Session timeout in ms (default: 900000 / 15 minutes, range: 30s - 24 hours)
147
- - `globalMetadata`: Metadata attached to all events
148
- - `samplingRate`: Event sampling rate 0-1 (default: 1.0)
149
- - `errorSampling`: Error sampling rate 0-1 (default: 1.0 / 100%)
150
- - `sensitiveQueryParams`: Query params to remove from URLs
151
- - `primaryScrollSelector`: Override automatic primary scroll container detection (e.g., `.mat-sidenav-content`, `window`)
152
- - `integrations`:
153
- - `tracelog.projectId`: TraceLog SaaS
154
- - `custom.collectApiUrl`: Custom backend
155
- - `custom.allowHttp`: Enable HTTP for testing
156
- - `googleAnalytics.measurementId`: GA4
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
-
163
- ## Event Data Structure
164
-
165
- Each event contains a base structure with type-specific data:
166
-
167
- **Base fields (all events):**
168
- - `id`: Unique event identifier
169
- - `type`: Event type (see below)
170
- - `page_url`: Current page URL
171
- - `timestamp`: Unix timestamp in milliseconds
172
- - `referrer`: Document referrer (optional)
173
- - `from_page_url`: Previous page URL (optional)
174
- - `utm`: UTM parameters (source, medium, campaign, term, content)
175
-
176
- **Event-specific data:**
177
-
178
- - **`PAGE_VIEW`**: Navigation tracking
179
- - `page_view.referrer`: Page referrer
180
- - `page_view.title`: Page title
181
- - `page_view.pathname`: URL pathname
182
- - `page_view.search`: Query string
183
- - `page_view.hash`: URL hash
184
-
185
- - **`CLICK`**: User interactions
186
- - `click_data.x/y`: Viewport coordinates
187
- - `click_data.relativeX/relativeY`: Element-relative position
188
- - `click_data.tag/id/class`: Element identifiers
189
- - `click_data.text/href/title/alt`: Element content
190
- - `click_data.role/ariaLabel`: Accessibility attributes
191
- - `click_data.dataAttributes`: Data attributes
192
-
193
- - **`SCROLL`**: Scroll engagement
194
- - `scroll_data.depth`: Scroll depth percentage (0-100)
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
213
-
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
217
-
218
- - **`SESSION_END`**: Session termination (synchronous flush before page unload)
219
- - `session_end_reason`: `inactivity`, `page_unload`, `manual_stop`, `orphaned_cleanup`, or `tab_closed`
220
-
221
- - **`CUSTOM`**: Business-specific events
222
- - `custom_event.name`: Event name
223
- - `custom_event.metadata`: Custom data (any JSON-serializable value)
224
-
225
- - **`WEB_VITALS`**: Performance metrics (only sent when exceeding quality thresholds)
226
- - `web_vitals.type`: Metric type (LCP, CLS, INP, FCP, TTFB, LONG_TASK)
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
230
-
231
- - **`ERROR`**: JavaScript errors
232
- - `error_data.type`: Error type (js_error, promise_rejection)
233
- - `error_data.message`: Error message
234
- - `error_data.filename/line/column`: Error location
235
-
236
- ## Advanced
237
-
238
- **Event subscription:**
72
+ ## Configuration
73
+
239
74
  ```typescript
240
- // Important: Register listeners BEFORE init() to capture initial events (SESSION_START, PAGE_VIEW)
241
- tracelog.on('event', (data) => console.log('Event:', data.type));
242
- tracelog.on('queue', (data) => console.log('Queued:', data.events.length));
75
+ await tracelog.init({
76
+ // Session
77
+ sessionTimeout: 900000, // 15 min (default)
243
78
 
244
- await tracelog.init();
245
- ```
79
+ // Sampling
80
+ samplingRate: 1.0, // 100% (default)
81
+ errorSampling: 1.0, // 100% (default)
246
82
 
247
- **Note**: Listeners are buffered if registered before `init()`, ensuring you don't miss initial events.
83
+ // Privacy
84
+ sensitiveQueryParams: ['token'], // Merged with defaults
248
85
 
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
- }
86
+ // Integrations
87
+ integrations: {
88
+ tracelog: { projectId: 'your-id' },
89
+ custom: { collectApiUrl: 'https://api.example.com/collect' },
90
+ googleAnalytics: { measurementId: 'G-XXXXXX' }
91
+ },
92
+
93
+ // Viewport tracking
94
+ viewport: {
95
+ elements: [
96
+ { selector: '.cta-button', id: 'pricing-cta', name: 'Pricing CTA' }
97
+ ],
98
+ threshold: 0.5, // 50% visible
99
+ minDwellTime: 1000 // 1 second
272
100
  }
273
101
  });
274
102
  ```
275
103
 
276
- **Analytics queries example:**
104
+ ### Methods
105
+
106
+ - `init(config?)` - Initialize tracking
107
+ - `event(name, metadata?)` - Send custom event
108
+ - `on(event, callback)` - Subscribe to events
109
+ - `off(event, callback)` - Unsubscribe
110
+ - `destroy()` - Cleanup
111
+
112
+ ## Event Types
113
+
114
+ All events include: `id`, `type`, `page_url`, `timestamp`, `sessionId`, `utm`
115
+
116
+ | Type | Data Fields |
117
+ |------|-------------|
118
+ | `PAGE_VIEW` | `page_view.{title, pathname, referrer}` |
119
+ | `CLICK` | `click_data.{x, y, tag, id, text, href}` |
120
+ | `SCROLL` | `scroll_data.{depth, direction, velocity, is_primary}` |
121
+ | `SESSION_START` | Session initialization |
122
+ | `SESSION_END` | `session_end_reason` |
123
+ | `CUSTOM` | `custom_event.{name, metadata}` |
124
+ | `WEB_VITALS` | `web_vitals.{type, value}` (LCP, CLS, INP, FCP, TTFB) |
125
+ | `ERROR` | `error_data.{type, message, filename, line}` |
126
+ | `VIEWPORT_VISIBLE` | `viewport_data.{selector, dwellTime, visibilityRatio}` |
127
+
128
+ ## Examples
129
+
130
+ ### Event Subscription
277
131
  ```typescript
278
- // In your analytics backend
279
- const primaryScrollEvents = events.filter(e =>
280
- e.type === 'scroll' && e.scroll_data.is_primary
281
- );
132
+ // Register BEFORE init() to catch initial events
133
+ tracelog.on('event', (event) => {
134
+ console.log(event.type, event);
135
+ });
282
136
 
283
- const avgPrimaryDepth = primaryScrollEvents.reduce((sum, e) =>
284
- sum + e.scroll_data.depth, 0
285
- ) / primaryScrollEvents.length;
137
+ tracelog.on('queue', (batch) => {
138
+ console.log('Queued:', batch.events.length);
139
+ });
286
140
 
287
- console.log(`Average primary content depth: ${avgPrimaryDepth}%`);
141
+ await tracelog.init();
288
142
  ```
289
143
 
290
- **TypeScript type helpers:**
144
+ ### Privacy Controls
291
145
  ```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
- }
146
+ // Exclude sensitive elements
147
+ <div data-tlog-ignore>
148
+ <input type="password">
149
+ </div>
301
150
 
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
- }
151
+ // Filter URL params
152
+ await tracelog.init({
153
+ sensitiveQueryParams: ['affiliate_id', 'promo'],
154
+ samplingRate: 0.5 // Track 50% of users
307
155
  });
308
156
  ```
309
157
 
310
- **Multiple integrations:**
158
+ ### Filter Primary Scroll
311
159
  ```typescript
312
- await tracelog.init({
313
- integrations: {
314
- tracelog: { projectId: 'your-project-id' },
315
- googleAnalytics: { measurementId: 'G-XXXXXXXXXX' }
160
+ tracelog.on('event', (event) => {
161
+ if (event.type === 'scroll' && event.scroll_data.is_primary) {
162
+ console.log('Main content scroll:', event.scroll_data.depth);
316
163
  }
317
164
  });
318
165
  ```
319
166
 
320
- **Disable globally:**
167
+ ### Global Disable
321
168
  ```typescript
322
169
  window.__traceLogDisabled = true;
323
170
  ```
324
171
 
325
- ### Manual Primary Container Selection
172
+ ## Privacy & Security
326
173
 
327
- For edge cases requiring manual override of automatic primary container detection:
174
+ - **PII Sanitization** - Auto-redacts emails, phones, credit cards, API keys
175
+ - **Input Protection** - Never captures input/textarea/select values
176
+ - **URL Filtering** - Removes sensitive query params (token, auth, key, password, etc.)
177
+ - **Element Exclusion** - Use `data-tlog-ignore` attribute
178
+ - **Client-Side Controls** - All validation/sampling happens in browser
328
179
 
329
- ```typescript
330
- await tracelog.init({
331
- primaryScrollSelector: '#custom-content' // Override auto-detection
332
- });
180
+ **Your Responsibilities:**
181
+ - Get user consent before calling `init()` (GDPR)
182
+ - Sanitize custom event metadata
183
+ - Call `destroy()` on consent revoke
333
184
 
334
- // To mark window as primary:
335
- await tracelog.init({
336
- primaryScrollSelector: 'window'
337
- });
338
- ```
185
+ [Full Security Guide →](./SECURITY.md)
339
186
 
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
187
+ ## Error Handling
343
188
 
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
-
351
- ## Compatibility
352
-
353
- - **Runtime**: Modern browsers (Chrome 60+, Firefox 55+, Safari 12+)
354
- - **Module formats**: ESM, CommonJS
355
- - **TypeScript**: Full type definitions included
356
- - **Frameworks**: React, Vue, Angular, Svelte, vanilla JS
189
+ - **4xx errors** - Events discarded (no retry)
190
+ - **5xx/network errors** - Events persist in localStorage for next-page recovery
191
+ - **Page unload** - Uses `sendBeacon()` for reliable delivery
192
+ - **Event expiry** - Persisted events expire after 2 hours
357
193
 
358
194
  ## Debug
359
195
 
360
- Enable QA mode: `?tlog_mode=qa` URL parameter
196
+ Enable QA mode: `?tlog_mode=qa`
361
197
 
362
198
  ```typescript
363
- tracelog.init();
364
199
  console.log(tracelog.isInitialized()); // true
365
200
  ```
366
201
 
367
- ## Error Handling & Event Persistence
368
-
369
- TraceLog uses a hybrid sendBeacon/fetch strategy with intelligent error handling:
370
-
371
- ### Send Strategy
372
-
373
- - **Async events (normal operation)**: Uses `fetch` with full HTTP error detection
374
- - Detects 4xx/5xx errors and handles them appropriately
375
- - Returns detailed error information for debugging
376
-
377
- - **Sync events (page unload, session end)**: Uses `sendBeacon` for guaranteed delivery
378
- - Browser queues the request even if the page is closing
379
- - No HTTP error feedback available (limitation of sendBeacon API)
380
-
381
- ### Error Handling
382
-
383
- - **Permanent errors (4xx)**: Events are discarded immediately
384
- - `400 Bad Request`, `403 Forbidden`, `404 Not Found` → No persistence, no retry
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
387
-
388
- - **Temporary errors (5xx, network failures)**: Events persist in localStorage
389
- - `500`, `502`, `503`, `504` → Events saved for recovery on next page load
390
- - Network failures → Events persist and recover automatically
391
- - **No automatic in-session retries** to avoid performance impact and battery drain
392
- - Recovery attempted on next page load via `recoverPersistedEvents()`
393
-
394
- - **Event expiry**: Persisted events expire after 2 hours to prevent stale data recovery
395
-
396
- See [SenderManager docs](./src/managers/README.md#sendermanager) for complete error handling details.
202
+ ## Development
397
203
 
398
- ### sendBeacon Limitations
399
-
400
- When using `sendBeacon` (page unload scenarios):
401
- - Browser only returns `true` (queued) or `false` (rejected)
402
- - No visibility into HTTP response codes (403, 500, etc.)
403
- - Events failing server-side validation won't be detected
404
- - Accepted events are persisted as fallback and cleared on next successful session
405
-
406
- ## Troubleshooting
407
-
408
- - **Session issues**: Check localStorage availability and session timeout. See [SessionManager docs](./src/managers/README.md#sessionmanager)
409
- - **Memory usage**: Reduce `sessionTimeout`, lower `samplingRate`, call `destroy()` on cleanup
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
416
- - **CI failures**: Verify Playwright installation and Node.js ≥20
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
-
422
- ## Development & Contributing
423
-
424
- ### Development Setup
425
204
  ```bash
426
- git clone https://github.com/nacorga/tracelog-lib.git
427
- cd tracelog-lib
428
205
  npm install
429
- npm run build:all # Build ESM + CJS + Browser
430
- npm run check # Lint + format check
431
- npm run test:e2e # Run E2E tests
432
- npm run test:unit # Run unit tests
433
- npm run test:coverage # Run tests with coverage
206
+ npm run build:all # ESM + CJS + Browser
207
+ npm run check # Lint + format
208
+ npm run test # All tests
209
+ npm run test:coverage # With coverage
434
210
  ```
435
211
 
436
- ### Workflow
212
+ ## Browser Support
437
213
 
438
- 1. Create feature branch
439
- 2. Submit PR to `main`
440
- 3. CI validates: security, quality, build, tests
441
- 4. Merge after approval
442
- 5. Release via GitHub Actions
214
+ Chrome 60+, Firefox 55+, Safari 12+, Edge 79+
443
215
 
444
- ## Testing
216
+ ## Documentation
445
217
 
446
- ```bash
447
- npm run docs:dev # Demo at localhost:3000
448
- npm run test:unit # Unit tests
449
- npm run test:e2e # E2E tests
450
- ```
218
+ - [Handlers](./src/handlers/README.md) - Event capture implementation
219
+ - [Managers](./src/managers/README.md) - Core components
220
+ - [Security](./SECURITY.md) - Privacy & security guide
221
+ - [Changelog](./CHANGELOG.md) - Release history
451
222
 
452
223
  ## License
453
224
 
454
- MIT © TraceLog. See [LICENSE](LICENSE) file for details.
455
-
456
- ## Acknowledgments
457
-
458
- Built with [web-vitals](https://github.com/GoogleChrome/web-vitals) for performance metrics. Inspired by privacy-first analytics tools and modern web standards for user behavior tracking.
225
+ MIT © TraceLog