swetrix 4.2.0 → 4.4.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 +84 -8
- package/dist/esnext/Lib.d.ts +77 -11
- package/dist/esnext/Lib.js +536 -11
- package/dist/esnext/Lib.js.map +1 -1
- package/dist/esnext/index.d.ts +18 -15
- package/dist/esnext/index.js +23 -15
- package/dist/esnext/index.js.map +1 -1
- package/dist/replaylibrary.min.js +173 -0
- package/dist/swetrix.cjs.js +563 -25
- package/dist/swetrix.cjs.js.map +1 -1
- package/dist/swetrix.es5.js +563 -26
- package/dist/swetrix.es5.js.map +1 -1
- package/dist/swetrix.js +1 -1
- package/dist/swetrix.js.map +1 -1
- package/jest.config.js +2 -0
- package/package.json +10 -7
- package/rollup.config.mjs +20 -0
- package/src/Lib.ts +751 -12
- package/src/index.ts +29 -14
- package/src/types/rrweb-shim.d.ts +11 -0
- package/tests/sessionReplay.test.ts +600 -0
- package/tsconfig.esnext.json +5 -1
- package/tsconfig.json +6 -1
- package/tsconfig.test.json +7 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/swetrix)
|
|
8
8
|
[](https://bundlephobia.com/package/swetrix)
|
|
9
|
-
[](https://
|
|
9
|
+
[](https://www.jsdelivr.com/package/npm/swetrix)
|
|
10
10
|
[](https://github.com/swetrix/swetrix-js/issues)
|
|
11
11
|
|
|
12
12
|
# Swetrix Tracking Script
|
|
@@ -65,6 +65,7 @@ init('YOUR_PROJECT_ID', {
|
|
|
65
65
|
disabled: false,
|
|
66
66
|
respectDNT: false,
|
|
67
67
|
profileId: 'user-123',
|
|
68
|
+
preloadSessionReplay: false,
|
|
68
69
|
})
|
|
69
70
|
```
|
|
70
71
|
|
|
@@ -75,6 +76,7 @@ init('YOUR_PROJECT_ID', {
|
|
|
75
76
|
| `disabled` | When `true`, no data is sent. Useful for dev environments. | `false` |
|
|
76
77
|
| `respectDNT` | When `true`, disables tracking for users with Do Not Track enabled. | `false` |
|
|
77
78
|
| `profileId` | Profile ID for long-term user tracking (MAU/DAU). | `undefined` |
|
|
79
|
+
| `preloadSessionReplay` | Preload the session replay recorder after `init()`. Recording only starts after `startSessionReplay()`. | `undefined` |
|
|
78
80
|
|
|
79
81
|
### `trackViews(options?)`
|
|
80
82
|
|
|
@@ -110,6 +112,7 @@ track({
|
|
|
110
112
|
ev: 'signup',
|
|
111
113
|
unique: true,
|
|
112
114
|
meta: { plan: 'pro', source: 'landing' },
|
|
115
|
+
profileId: 'user-123',
|
|
113
116
|
})
|
|
114
117
|
```
|
|
115
118
|
|
|
@@ -118,6 +121,7 @@ track({
|
|
|
118
121
|
| `ev` | Event name (max 256 chars). | **required** |
|
|
119
122
|
| `unique` | Only count once per session. | `false` |
|
|
120
123
|
| `meta` | Key-value metadata (max 20 keys, 1000 chars total). | `{}` |
|
|
124
|
+
| `profileId` | Optional profile ID. Overrides the global `profileId` for this event. | `undefined` |
|
|
121
125
|
|
|
122
126
|
### `trackErrors(options?)`
|
|
123
127
|
|
|
@@ -161,29 +165,101 @@ pageview({
|
|
|
161
165
|
### Feature Flags
|
|
162
166
|
|
|
163
167
|
```javascript
|
|
164
|
-
// Get all flags
|
|
168
|
+
// Get all flags. Results are cached for 5 minutes.
|
|
165
169
|
const flags = await getFeatureFlags({ profileId: 'user-123' })
|
|
166
170
|
|
|
167
|
-
//
|
|
171
|
+
// Force a fresh fetch
|
|
172
|
+
const freshFlags = await getFeatureFlags({ profileId: 'user-123' }, true)
|
|
173
|
+
|
|
174
|
+
// Get a single flag. The third argument is an optional fallback value.
|
|
168
175
|
const enabled = await getFeatureFlag('dark-mode', { profileId: 'user-123' })
|
|
176
|
+
const enabledWithFallback = await getFeatureFlag('dark-mode', { profileId: 'user-123' }, false)
|
|
169
177
|
|
|
170
|
-
// Clear cache
|
|
178
|
+
// Clear the shared feature flag / experiment cache
|
|
171
179
|
clearFeatureFlagsCache()
|
|
172
180
|
```
|
|
173
181
|
|
|
174
182
|
### A/B Experiments
|
|
175
183
|
|
|
176
184
|
```javascript
|
|
177
|
-
// Get all
|
|
185
|
+
// Get all running experiment assignments. Results are cached for 5 minutes.
|
|
178
186
|
const experiments = await getExperiments({ profileId: 'user-123' })
|
|
179
187
|
|
|
180
|
-
//
|
|
181
|
-
const
|
|
188
|
+
// Force a fresh fetch
|
|
189
|
+
const freshExperiments = await getExperiments({ profileId: 'user-123' }, true)
|
|
182
190
|
|
|
183
|
-
//
|
|
191
|
+
// Get a specific experiment variant. The third argument is an optional fallback variant.
|
|
192
|
+
const variant = await getExperiment('checkout-redesign-experiment-id', { profileId: 'user-123' })
|
|
193
|
+
const variantWithFallback = await getExperiment('checkout-redesign-experiment-id', { profileId: 'user-123' }, 'control')
|
|
194
|
+
|
|
195
|
+
// Clear the shared feature flag / experiment cache
|
|
184
196
|
clearExperimentsCache()
|
|
185
197
|
```
|
|
186
198
|
|
|
199
|
+
### `startSessionReplay(options?)`
|
|
200
|
+
|
|
201
|
+
Start recording a session replay. Session replays use `total` privacy by default, which masks text and inputs and blocks media/canvas capture unless you explicitly choose another mode.
|
|
202
|
+
|
|
203
|
+
If you use the npm package, rrweb is dynamically imported from your installed dependencies only when the recorder is preloaded or started. If you use the CDN/script-tag build, the standalone replay recorder is loaded with an async script tag.
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
const replay = await startSessionReplay({
|
|
207
|
+
privacy: 'total',
|
|
208
|
+
maskAllText: true,
|
|
209
|
+
sampleRate: 0.25,
|
|
210
|
+
maxDurationMs: 10 * 60 * 1000,
|
|
211
|
+
idleTimeoutMs: 2 * 60 * 1000,
|
|
212
|
+
maxBytesPerChunk: 512 * 1024,
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
// Stop or flush manually when needed
|
|
216
|
+
await replay.flush()
|
|
217
|
+
await replay.stop()
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
| Option | Description | Default |
|
|
221
|
+
|---|---|---|
|
|
222
|
+
| `privacy` | Privacy mode: `total`, `normal`, or `none`. | `'total'` |
|
|
223
|
+
| `maskAllText` | Mask all non-input text with asterisks. Defaults to `true` when `privacy` is `total`, otherwise `false`. | privacy-based |
|
|
224
|
+
| `sampleRate` | Fraction of sessions to record (`0` to `1`). | `1` |
|
|
225
|
+
| `maxDurationMs` | Stop recording after this duration. | `undefined` |
|
|
226
|
+
| `idleTimeoutMs` | Stop recording after this much visitor inactivity. | `undefined` |
|
|
227
|
+
| `flushIntervalMs` | Upload buffered replay events at this interval. | `5000` |
|
|
228
|
+
| `maxEventsPerChunk` | Upload once this many events are buffered. | `100` |
|
|
229
|
+
| `maxBytesPerChunk` | Upload once buffered replay events reach this approximate byte size. | `524288` |
|
|
230
|
+
| `maxBytesPerEvent` | Drop a single replay event if it is larger than this many bytes. | `5242880` |
|
|
231
|
+
| `recordIframes` | Allow iframe elements to be captured. Iframes are blocked by default to reduce replay size and avoid recording embedded third-party content. | `false` |
|
|
232
|
+
| `rrweb` | Additional rrweb record options. | `undefined` |
|
|
233
|
+
|
|
234
|
+
To mask text while keeping media less restricted than `total` privacy, combine `normal` privacy with `maskAllText`:
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
await startSessionReplay({
|
|
238
|
+
privacy: 'normal',
|
|
239
|
+
maskAllText: true,
|
|
240
|
+
})
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
By default, Swetrix blocks iframe elements from replay snapshots. If you own the iframe content and need it in the replay, opt in explicitly:
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
await startSessionReplay({
|
|
247
|
+
privacy: 'normal',
|
|
248
|
+
recordIframes: true,
|
|
249
|
+
})
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Cross-origin iframe recording also requires rrweb's cross-origin iframe support and should only be enabled for domains you control:
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
await startSessionReplay({
|
|
256
|
+
recordIframes: true,
|
|
257
|
+
rrweb: {
|
|
258
|
+
recordCrossOriginIframes: true,
|
|
259
|
+
},
|
|
260
|
+
})
|
|
261
|
+
```
|
|
262
|
+
|
|
187
263
|
### Session & Profile IDs
|
|
188
264
|
|
|
189
265
|
```javascript
|
package/dist/esnext/Lib.d.ts
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
type RrwebEvent = Record<string, unknown>;
|
|
2
|
+
type RrwebEmit = (event: RrwebEvent) => void;
|
|
3
|
+
interface RrwebRecordOptions {
|
|
4
|
+
emit?: RrwebEmit;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
interface RrwebGlobal {
|
|
8
|
+
record?: (options: RrwebRecordOptions) => (() => void) | undefined;
|
|
9
|
+
Replayer?: unknown;
|
|
10
|
+
}
|
|
11
|
+
type SessionReplayPreloadOption = boolean | {
|
|
12
|
+
rrwebUrl?: string;
|
|
13
|
+
};
|
|
14
|
+
declare global {
|
|
15
|
+
interface Window {
|
|
16
|
+
rrweb?: RrwebGlobal;
|
|
17
|
+
__SWETRIX_RRWEB_LOADING__?: Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
1
20
|
export interface LibOptions {
|
|
2
21
|
/**
|
|
3
22
|
* When set to `true`, localhost events will be sent to server.
|
|
@@ -19,6 +38,10 @@ export interface LibOptions {
|
|
|
19
38
|
* If set, it will be used for all pageviews and events unless overridden per-call.
|
|
20
39
|
*/
|
|
21
40
|
profileId?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Preload session replay recorder code. Recording only starts after calling startSessionReplay().
|
|
43
|
+
*/
|
|
44
|
+
preloadSessionReplay?: SessionReplayPreloadOption;
|
|
22
45
|
}
|
|
23
46
|
export interface TrackEventOptions {
|
|
24
47
|
/** The custom event name. */
|
|
@@ -117,6 +140,25 @@ export interface ErrorActions {
|
|
|
117
140
|
/** Stops the tracking of errors. */
|
|
118
141
|
stop: () => void;
|
|
119
142
|
}
|
|
143
|
+
declare const SESSION_REPLAY_PRIVACY_VALUES: readonly ["total", "normal", "none"];
|
|
144
|
+
export type SessionReplayPrivacy = (typeof SESSION_REPLAY_PRIVACY_VALUES)[number];
|
|
145
|
+
export interface SessionReplayOptions {
|
|
146
|
+
privacy?: SessionReplayPrivacy;
|
|
147
|
+
rrweb?: RrwebRecordOptions;
|
|
148
|
+
flushIntervalMs?: number;
|
|
149
|
+
maxEventsPerChunk?: number;
|
|
150
|
+
maxBytesPerChunk?: number;
|
|
151
|
+
maxBytesPerEvent?: number;
|
|
152
|
+
sampleRate?: number;
|
|
153
|
+
maxDurationMs?: number;
|
|
154
|
+
idleTimeoutMs?: number;
|
|
155
|
+
maskAllText?: boolean;
|
|
156
|
+
recordIframes?: boolean;
|
|
157
|
+
}
|
|
158
|
+
export interface SessionReplayActions {
|
|
159
|
+
stop: () => Promise<void>;
|
|
160
|
+
flush: () => Promise<void>;
|
|
161
|
+
}
|
|
120
162
|
export interface PageData {
|
|
121
163
|
/** Current URL path. */
|
|
122
164
|
path: string;
|
|
@@ -169,6 +211,7 @@ export interface PageViewsOptions {
|
|
|
169
211
|
export declare const defaultActions: {
|
|
170
212
|
stop(): void;
|
|
171
213
|
};
|
|
214
|
+
export declare const defaultSessionReplayActions: SessionReplayActions;
|
|
172
215
|
export declare class Lib {
|
|
173
216
|
private projectID;
|
|
174
217
|
private options?;
|
|
@@ -179,6 +222,9 @@ export declare class Lib {
|
|
|
179
222
|
private activePage;
|
|
180
223
|
private errorListenerExists;
|
|
181
224
|
private cachedData;
|
|
225
|
+
private rrwebLoader;
|
|
226
|
+
private sessionReplayActions;
|
|
227
|
+
private sessionReplayInitPromise;
|
|
182
228
|
constructor(projectID: string, options?: LibOptions | undefined);
|
|
183
229
|
captureError(event: ErrorEvent): void;
|
|
184
230
|
trackErrors(options?: ErrorOptions): ErrorActions;
|
|
@@ -187,10 +233,10 @@ export declare class Lib {
|
|
|
187
233
|
trackPageViews(options?: PageViewsOptions): PageActions;
|
|
188
234
|
getPerformanceStats(): IPerfPayload | {};
|
|
189
235
|
/**
|
|
190
|
-
* Fetches all feature flags
|
|
191
|
-
* Results are cached for 5 minutes by default.
|
|
236
|
+
* Fetches all feature flags for the project.
|
|
237
|
+
* Results are cached for 5 minutes by default and share a cache with experiments.
|
|
192
238
|
*
|
|
193
|
-
* @param options - Options for evaluating feature flags.
|
|
239
|
+
* @param options - Options for evaluating feature flags (`profileId` only).
|
|
194
240
|
* @param forceRefresh - If true, bypasses the cache and fetches fresh data.
|
|
195
241
|
* @returns A promise that resolves to a record of flag keys to boolean values.
|
|
196
242
|
*/
|
|
@@ -203,8 +249,8 @@ export declare class Lib {
|
|
|
203
249
|
* Gets the value of a single feature flag.
|
|
204
250
|
*
|
|
205
251
|
* @param key - The feature flag key.
|
|
206
|
-
* @param options - Options for evaluating the feature flag.
|
|
207
|
-
* @param defaultValue -
|
|
252
|
+
* @param options - Options for evaluating the feature flag (`profileId` only).
|
|
253
|
+
* @param defaultValue - Optional default value to return if the flag is not found. Defaults to false.
|
|
208
254
|
* @returns A promise that resolves to the boolean value of the flag.
|
|
209
255
|
*/
|
|
210
256
|
getFeatureFlag(key: string, options?: FeatureFlagsOptions, defaultValue?: boolean): Promise<boolean>;
|
|
@@ -213,16 +259,16 @@ export declare class Lib {
|
|
|
213
259
|
*/
|
|
214
260
|
clearFeatureFlagsCache(): void;
|
|
215
261
|
/**
|
|
216
|
-
* Fetches
|
|
262
|
+
* Fetches variant assignments for running A/B test experiments returned by feature flag evaluation.
|
|
217
263
|
* Results are cached for 5 minutes by default (shared cache with feature flags).
|
|
218
264
|
*
|
|
219
|
-
* @param options - Options for evaluating experiments.
|
|
265
|
+
* @param options - Options for evaluating experiments (`profileId` only).
|
|
220
266
|
* @param forceRefresh - If true, bypasses the cache and fetches fresh data.
|
|
221
267
|
* @returns A promise that resolves to a record of experiment IDs to variant keys.
|
|
222
268
|
*
|
|
223
269
|
* @example
|
|
224
270
|
* ```typescript
|
|
225
|
-
* const experiments = await getExperiments()
|
|
271
|
+
* const experiments = await getExperiments({ profileId: 'user-123' })
|
|
226
272
|
* // experiments = { 'exp-123': 'variant-a', 'exp-456': 'control' }
|
|
227
273
|
* ```
|
|
228
274
|
*/
|
|
@@ -231,13 +277,16 @@ export declare class Lib {
|
|
|
231
277
|
* Gets the variant key for a specific A/B test experiment.
|
|
232
278
|
*
|
|
233
279
|
* @param experimentId - The experiment ID.
|
|
234
|
-
* @param options - Options for evaluating the experiment.
|
|
235
|
-
* @param defaultVariant -
|
|
280
|
+
* @param options - Options for evaluating the experiment (`profileId` only).
|
|
281
|
+
* @param defaultVariant - Optional default variant key to return if the experiment is not found. Defaults to null.
|
|
236
282
|
* @returns A promise that resolves to the variant key assigned to this user, or defaultVariant if not found.
|
|
237
283
|
*
|
|
238
284
|
* @example
|
|
239
285
|
* ```typescript
|
|
240
|
-
* const variant = await getExperiment('checkout-redesign')
|
|
286
|
+
* const variant = await getExperiment('checkout-redesign', { profileId: 'user-123' })
|
|
287
|
+
*
|
|
288
|
+
* // Optional fallback variant:
|
|
289
|
+
* const variantWithFallback = await getExperiment('checkout-redesign', undefined, 'control')
|
|
241
290
|
*
|
|
242
291
|
* if (variant === 'new-checkout') {
|
|
243
292
|
* // Show new checkout flow
|
|
@@ -298,6 +347,10 @@ export declare class Lib {
|
|
|
298
347
|
* ```
|
|
299
348
|
*/
|
|
300
349
|
getSessionId(): Promise<string | null>;
|
|
350
|
+
startSessionReplay(options?: SessionReplayOptions): Promise<SessionReplayActions>;
|
|
351
|
+
private initialiseSessionReplay;
|
|
352
|
+
private shouldSampleSessionReplay;
|
|
353
|
+
private getSessionReplayPrivacy;
|
|
301
354
|
/**
|
|
302
355
|
* Gets the API base URL (without /log suffix).
|
|
303
356
|
*/
|
|
@@ -307,6 +360,19 @@ export declare class Lib {
|
|
|
307
360
|
private trackPage;
|
|
308
361
|
submitPageView(payload: Partial<IPageViewPayload>, unique: boolean, perf: IPerfPayload | {}, evokeCallback?: boolean): void;
|
|
309
362
|
private canTrack;
|
|
363
|
+
private getSessionReplayUrl;
|
|
364
|
+
private getSessionReplayPreloadOption;
|
|
365
|
+
private getDefaultSessionReplayUrl;
|
|
366
|
+
private getTrackerScript;
|
|
367
|
+
private preloadSessionReplay;
|
|
368
|
+
private loadSessionReplayRecorder;
|
|
369
|
+
private loadSessionReplayPackage;
|
|
370
|
+
private loadSessionReplayScript;
|
|
371
|
+
private getSessionReplayRecordOptions;
|
|
372
|
+
private mergeSelectors;
|
|
373
|
+
private createReplayId;
|
|
374
|
+
private sendSessionReplayStart;
|
|
375
|
+
private sendSessionReplayChunk;
|
|
310
376
|
private sendRequest;
|
|
311
377
|
}
|
|
312
378
|
export {};
|