@tracelog/lib 0.10.0 → 0.11.1
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 +128 -407
- package/dist/browser/tracelog.esm.js +1173 -771
- 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/app.d.ts +2 -0
- package/dist/cjs/app.d.ts.map +1 -1
- package/dist/cjs/app.js +5 -0
- package/dist/cjs/app.js.map +1 -1
- package/dist/cjs/constants/config.constants.d.ts +26 -1
- package/dist/cjs/constants/config.constants.d.ts.map +1 -1
- package/dist/cjs/constants/config.constants.js +30 -3
- package/dist/cjs/constants/config.constants.js.map +1 -1
- package/dist/cjs/constants/error.constants.d.ts +15 -0
- package/dist/cjs/constants/error.constants.d.ts.map +1 -1
- package/dist/cjs/constants/error.constants.js +19 -1
- package/dist/cjs/constants/error.constants.js.map +1 -1
- package/dist/cjs/handlers/click.handler.d.ts +15 -0
- package/dist/cjs/handlers/click.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/click.handler.js +69 -0
- package/dist/cjs/handlers/click.handler.js.map +1 -1
- package/dist/cjs/handlers/error.handler.d.ts +7 -0
- package/dist/cjs/handlers/error.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/error.handler.js +35 -0
- package/dist/cjs/handlers/error.handler.js.map +1 -1
- package/dist/cjs/handlers/page-view.handler.d.ts +1 -0
- package/dist/cjs/handlers/page-view.handler.d.ts.map +1 -1
- package/dist/cjs/handlers/page-view.handler.js +11 -0
- package/dist/cjs/handlers/page-view.handler.js.map +1 -1
- package/dist/cjs/handlers/performance.handler.js +5 -5
- package/dist/cjs/handlers/performance.handler.js.map +1 -1
- package/dist/cjs/handlers/viewport.handler.d.ts +44 -0
- package/dist/cjs/handlers/viewport.handler.d.ts.map +1 -0
- package/dist/cjs/handlers/viewport.handler.js +286 -0
- package/dist/cjs/handlers/viewport.handler.js.map +1 -0
- package/dist/cjs/managers/event.manager.d.ts +23 -3
- package/dist/cjs/managers/event.manager.d.ts.map +1 -1
- package/dist/cjs/managers/event.manager.js +166 -10
- 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 +12 -0
- package/dist/cjs/managers/sender.manager.js.map +1 -1
- package/dist/cjs/types/config.types.d.ts +9 -0
- package/dist/cjs/types/config.types.d.ts.map +1 -1
- package/dist/cjs/types/config.types.js.map +1 -1
- package/dist/cjs/types/event.types.d.ts +140 -16
- package/dist/cjs/types/event.types.d.ts.map +1 -1
- package/dist/cjs/types/event.types.js +23 -9
- package/dist/cjs/types/event.types.js.map +1 -1
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +2 -0
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/scroll.types.d.ts +16 -0
- package/dist/cjs/types/scroll.types.d.ts.map +1 -0
- package/dist/cjs/types/scroll.types.js +12 -0
- package/dist/cjs/types/scroll.types.js.map +1 -0
- package/dist/cjs/types/viewport.types.d.ts +55 -0
- package/dist/cjs/types/viewport.types.d.ts.map +1 -0
- package/dist/cjs/types/viewport.types.js +3 -0
- package/dist/cjs/types/viewport.types.js.map +1 -0
- package/dist/cjs/utils/validations/config-validations.utils.d.ts.map +1 -1
- package/dist/cjs/utils/validations/config-validations.utils.js +91 -0
- package/dist/cjs/utils/validations/config-validations.utils.js.map +1 -1
- package/dist/esm/app.d.ts +2 -0
- package/dist/esm/app.d.ts.map +1 -1
- package/dist/esm/app.js +5 -0
- package/dist/esm/app.js.map +1 -1
- package/dist/esm/constants/config.constants.d.ts +26 -1
- package/dist/esm/constants/config.constants.d.ts.map +1 -1
- package/dist/esm/constants/config.constants.js +28 -1
- package/dist/esm/constants/config.constants.js.map +1 -1
- package/dist/esm/constants/error.constants.d.ts +15 -0
- package/dist/esm/constants/error.constants.d.ts.map +1 -1
- package/dist/esm/constants/error.constants.js +18 -0
- package/dist/esm/constants/error.constants.js.map +1 -1
- package/dist/esm/handlers/click.handler.d.ts +15 -0
- package/dist/esm/handlers/click.handler.d.ts.map +1 -1
- package/dist/esm/handlers/click.handler.js +70 -1
- package/dist/esm/handlers/click.handler.js.map +1 -1
- package/dist/esm/handlers/error.handler.d.ts +7 -0
- package/dist/esm/handlers/error.handler.d.ts.map +1 -1
- package/dist/esm/handlers/error.handler.js +36 -1
- package/dist/esm/handlers/error.handler.js.map +1 -1
- package/dist/esm/handlers/page-view.handler.d.ts +1 -0
- package/dist/esm/handlers/page-view.handler.d.ts.map +1 -1
- package/dist/esm/handlers/page-view.handler.js +11 -0
- package/dist/esm/handlers/page-view.handler.js.map +1 -1
- package/dist/esm/handlers/performance.handler.js +5 -5
- package/dist/esm/handlers/performance.handler.js.map +1 -1
- package/dist/esm/handlers/viewport.handler.d.ts +44 -0
- package/dist/esm/handlers/viewport.handler.d.ts.map +1 -0
- package/dist/esm/handlers/viewport.handler.js +282 -0
- package/dist/esm/handlers/viewport.handler.js.map +1 -0
- package/dist/esm/managers/event.manager.d.ts +23 -3
- package/dist/esm/managers/event.manager.d.ts.map +1 -1
- package/dist/esm/managers/event.manager.js +167 -11
- 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 +13 -1
- package/dist/esm/managers/sender.manager.js.map +1 -1
- package/dist/esm/types/config.types.d.ts +9 -0
- package/dist/esm/types/config.types.d.ts.map +1 -1
- package/dist/esm/types/config.types.js.map +1 -1
- package/dist/esm/types/event.types.d.ts +140 -16
- package/dist/esm/types/event.types.d.ts.map +1 -1
- package/dist/esm/types/event.types.js +23 -7
- package/dist/esm/types/event.types.js.map +1 -1
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/scroll.types.d.ts +16 -0
- package/dist/esm/types/scroll.types.d.ts.map +1 -0
- package/dist/esm/types/scroll.types.js +8 -0
- package/dist/esm/types/scroll.types.js.map +1 -0
- package/dist/esm/types/viewport.types.d.ts +55 -0
- package/dist/esm/types/viewport.types.d.ts.map +1 -0
- package/dist/esm/types/viewport.types.js +2 -0
- package/dist/esm/types/viewport.types.js.map +1 -0
- package/dist/esm/utils/validations/config-validations.utils.d.ts.map +1 -1
- package/dist/esm/utils/validations/config-validations.utils.js +92 -1
- package/dist/esm/utils/validations/config-validations.utils.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,35 +1,19 @@
|
|
|
1
|
-
# TraceLog
|
|
1
|
+
# TraceLog
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **Lightweight** -
|
|
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
|
-
|
|
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,468 +21,205 @@ npm install @tracelog/lib
|
|
|
37
21
|
```typescript
|
|
38
22
|
import { tracelog } from '@tracelog/lib';
|
|
39
23
|
|
|
40
|
-
// Standalone mode (no backend
|
|
41
|
-
tracelog.init();
|
|
24
|
+
// Standalone mode (no backend)
|
|
25
|
+
await tracelog.init();
|
|
42
26
|
|
|
43
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
75
|
+
await tracelog.init({
|
|
76
|
+
// Session
|
|
77
|
+
sessionTimeout: 900000, // 15 min (default)
|
|
243
78
|
|
|
244
|
-
|
|
245
|
-
|
|
79
|
+
// Sampling
|
|
80
|
+
samplingRate: 1.0, // 100% (default)
|
|
81
|
+
errorSampling: 1.0, // 100% (default)
|
|
246
82
|
|
|
247
|
-
|
|
83
|
+
// Privacy
|
|
84
|
+
sensitiveQueryParams: ['token'], // Merged with defaults
|
|
248
85
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
tracelog
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
);
|
|
132
|
+
// Register BEFORE init() to catch initial events
|
|
133
|
+
tracelog.on('event', (event) => {
|
|
134
|
+
console.log(event.type, event);
|
|
135
|
+
});
|
|
282
136
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
)
|
|
137
|
+
tracelog.on('queue', (batch) => {
|
|
138
|
+
console.log('Queued:', batch.events.length);
|
|
139
|
+
});
|
|
286
140
|
|
|
287
|
-
|
|
141
|
+
await tracelog.init();
|
|
288
142
|
```
|
|
289
143
|
|
|
290
|
-
|
|
144
|
+
### Privacy Controls
|
|
291
145
|
```typescript
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
158
|
+
### Filter Primary Scroll
|
|
311
159
|
```typescript
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
-
|
|
167
|
+
### Global Disable
|
|
321
168
|
```typescript
|
|
322
169
|
window.__traceLogDisabled = true;
|
|
323
170
|
```
|
|
324
171
|
|
|
325
|
-
|
|
172
|
+
## Privacy & Security
|
|
326
173
|
|
|
327
|
-
|
|
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
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
|
|
335
|
-
await tracelog.init({
|
|
336
|
-
primaryScrollSelector: 'window'
|
|
337
|
-
});
|
|
338
|
-
```
|
|
185
|
+
[Full Security Guide →](./SECURITY.md)
|
|
339
186
|
|
|
340
|
-
|
|
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
|
-
**
|
|
345
|
-
-
|
|
346
|
-
-
|
|
347
|
-
-
|
|
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`
|
|
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
|
-
##
|
|
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()`
|
|
202
|
+
## Development
|
|
393
203
|
|
|
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.
|
|
397
|
-
|
|
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 #
|
|
430
|
-
npm run check # Lint + format
|
|
431
|
-
npm run test
|
|
432
|
-
npm run test:
|
|
433
|
-
npm run test:coverage # Run tests with coverage
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### Workflow
|
|
437
|
-
|
|
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
|
|
443
|
-
|
|
444
|
-
## Testing
|
|
445
|
-
|
|
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
|
|
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
|
|
450
210
|
```
|
|
451
211
|
|
|
452
|
-
##
|
|
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
|
|
212
|
+
## Browser Support
|
|
465
213
|
|
|
466
|
-
|
|
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
|
-
```
|
|
214
|
+
Chrome 60+, Firefox 55+, Safari 12+, Edge 79+
|
|
474
215
|
|
|
475
|
-
|
|
476
|
-
```typescript
|
|
477
|
-
await tracelog.init({
|
|
478
|
-
sensitiveQueryParams: ['affiliate_id', 'promo_code'] // Merged with defaults
|
|
479
|
-
});
|
|
480
|
-
```
|
|
216
|
+
## Documentation
|
|
481
217
|
|
|
482
|
-
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
-
---
|
|
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
|
|
497
222
|
|
|
498
223
|
## License
|
|
499
224
|
|
|
500
|
-
MIT © TraceLog
|
|
501
|
-
|
|
502
|
-
## Acknowledgments
|
|
503
|
-
|
|
504
|
-
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
|