mixpanel-browser 2.72.0 → 2.74.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 (44) hide show
  1. package/.claude/settings.local.json +5 -2
  2. package/.eslintrc.json +7 -4
  3. package/.github/workflows/integration-tests.yml +52 -0
  4. package/.github/workflows/unit-tests.yml +40 -0
  5. package/CHANGELOG.md +12 -0
  6. package/README.md +1 -1
  7. package/build.sh +1 -5
  8. package/dist/mixpanel-core.cjs.d.ts +49 -4
  9. package/dist/mixpanel-core.cjs.js +244 -26
  10. package/dist/mixpanel-recorder.js +5258 -688
  11. package/dist/mixpanel-recorder.min.js +1 -1
  12. package/dist/mixpanel-recorder.min.js.map +1 -1
  13. package/dist/mixpanel-with-async-recorder.cjs.d.ts +49 -4
  14. package/dist/mixpanel-with-async-recorder.cjs.js +244 -26
  15. package/dist/mixpanel-with-recorder.d.ts +49 -4
  16. package/dist/mixpanel-with-recorder.js +6858 -2099
  17. package/dist/mixpanel-with-recorder.min.d.ts +49 -4
  18. package/dist/mixpanel-with-recorder.min.js +1 -1
  19. package/dist/mixpanel.amd.d.ts +49 -4
  20. package/dist/mixpanel.amd.js +6858 -2099
  21. package/dist/mixpanel.cjs.d.ts +49 -4
  22. package/dist/mixpanel.cjs.js +6858 -2099
  23. package/dist/mixpanel.globals.js +244 -26
  24. package/dist/mixpanel.min.js +175 -171
  25. package/dist/mixpanel.module.d.ts +49 -4
  26. package/dist/mixpanel.module.js +6858 -2099
  27. package/dist/mixpanel.umd.d.ts +49 -4
  28. package/dist/mixpanel.umd.js +6858 -2099
  29. package/dist/rrweb-bundled.js +4315 -591
  30. package/dist/rrweb-compiled.js +4962 -641
  31. package/package.json +30 -5
  32. package/rollup.config.mjs +254 -224
  33. package/src/autocapture/utils.js +15 -7
  34. package/src/config.js +1 -1
  35. package/src/index.d.ts +49 -4
  36. package/src/mixpanel-core.js +215 -15
  37. package/src/recorder/masking.js +197 -0
  38. package/src/recorder/rrweb-entrypoint.js +2 -1
  39. package/src/recorder/session-recording.js +43 -4
  40. package/src/recorder/utils.js +5 -1
  41. package/src/utils.js +11 -2
  42. package/src/window.js +3 -1
  43. package/testServer.js +51 -7
  44. package/.github/workflows/tests.yml +0 -25
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(mkdir:*)"
4
+ "Bash(mkdir:*)",
5
+ "Bash(cat:*)",
6
+ "Bash(node --input-type=module -e \"import { expect } from 'chai'; console.log\\('works'\\);\":*)",
7
+ "Bash(BABEL_ENV=test node:*)"
5
8
  ],
6
9
  "deny": [],
7
10
  "ask": []
8
11
  }
9
- }
12
+ }
package/.eslintrc.json CHANGED
@@ -8,7 +8,9 @@
8
8
  "sourceType": "module"
9
9
  },
10
10
  "rules": {
11
- "camelcase": "error",
11
+ "camelcase": ["error", {
12
+ "properties": "never"
13
+ }],
12
14
  "eol-last": "error",
13
15
  "eqeqeq": "error",
14
16
  "indent":
@@ -29,13 +31,14 @@
29
31
  ]
30
32
  },
31
33
  "overrides": [{
32
- "files": ["tests/unit/**/*.js"],
34
+ "files": ["tests/unit/**/*.js", "tests/browser/**/*.js", "*.mjs"],
33
35
  "parserOptions": {
34
- "ecmaVersion": 8,
36
+ "ecmaVersion": 9,
35
37
  "sourceType": "module"
36
38
  },
37
39
  "env": {
38
- "mocha": true
40
+ "mocha": true,
41
+ "node": true
39
42
  },
40
43
  "rules": {
41
44
  "camelcase": "error",
@@ -0,0 +1,52 @@
1
+ name: Integration Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+
13
+ permissions:
14
+ contents: read
15
+ checks: write # for dorny/test-reporter to post results
16
+
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ browser: [chrome-latest, edge-latest, safari-latest, firefox-latest, ios-safari-sim, android-chrome-sim]
21
+
22
+ env:
23
+ SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
24
+ SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
25
+ SAUCE_TUNNEL_NAME: ci-js-sdk-test-${{ matrix.browser }}-${{ github.run_id }}
26
+
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - name: Use Node.js 22.x
30
+ uses: actions/setup-node@v4
31
+ with:
32
+ node-version: 22.x
33
+
34
+ - name: Install Dependencies
35
+ run: npm ci
36
+
37
+ - name: Build
38
+ run: npm run build-full
39
+
40
+ - name: Sauce test
41
+ # for some reason, android emulator tests don't work with localhost so we need an IP to give to the runner...
42
+ run: BROWSER=${{ matrix.browser }} ROOT_DIR=$(pwd) SAUCE_HOST=$(hostname -I | awk '{print $1; exit}') npm run integration-test:sauce
43
+
44
+ - name: Test Report
45
+ uses: dorny/test-reporter@7b7927aa7da8b82e81e755810cb51f39941a2cc7 # v2
46
+ if: success() || failure() # run this step even if previous step failed
47
+ with:
48
+ name: Browser Tests # Name of the check run which will be created
49
+ reporter: mocha-json # Format of test results
50
+ path: 'tests/browser/results/*.json' # Path to test results
51
+ list-tests: 'failed'
52
+ fail-on-error: 'false'
@@ -0,0 +1,40 @@
1
+ name: Unit Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+
13
+ permissions:
14
+ contents: read
15
+ checks: write # for dorny/test-reporter to post results
16
+
17
+ strategy:
18
+ matrix:
19
+ node-version: [20.x, 22.x]
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - name: Use Node.js ${{ matrix.node-version }}
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: ${{ matrix.node-version }}
27
+ - run: npm ci
28
+ - run: npm run test:ci
29
+ - run: npm run build-dist
30
+
31
+ - name: Test Report
32
+ uses: dorny/test-reporter@7b7927aa7da8b82e81e755810cb51f39941a2cc7 # v2
33
+ if: success() || failure()
34
+ with:
35
+ name: Unit Tests
36
+ reporter: mocha-json
37
+ path: 'tests/unit/results/*.json'
38
+ list-tests: 'failed'
39
+ fail-on-error: 'false'
40
+
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ **2.74.0** (27 Jan 2026)
2
+ - New session recording masking configuration options, including the ability to unmask inputs and allowlist-based selector masking.
3
+ - Adds initial support for the remote settings API, allowing remote configuration of SDK config options.
4
+ - Adds new automated browser test suite that runs in CI and locally in chrome headless. See tests/browser/README.html for more information.
5
+ - Fixes type definitions for api_routes
6
+ - Removes outdated examples in the examples/ dir
7
+
8
+ **2.73.0** (23 Dec 2025)
9
+ - Adds several new hooks: `before_identify`, `before_register`, `before_register_once`, `before_track`, `before_unregister`
10
+ - Adds instance-initialization notification to allow Data Inspector browser extension to hook into SDK actions
11
+ - Fixes and extends type definitions
12
+
1
13
  **2.72.0** (14 Nov 2025)
2
14
  - Adds Autocapture rage-click configuration option `interactive_elements_only`, to ignore clicks on non-interactive page elements such as text. Configure with: `mixpanel.init('<TOKEN>', {autocapture: {rage_click: {interactive_elements_only: true}}})`
3
15
  - Adds TypeScript types for Feature Flags subsystem (`mixpanel.flags`)
package/README.md CHANGED
@@ -67,7 +67,7 @@ mixpanel.init('YOUR_TOKEN', {autocapture: true, debug: true, persistence: 'local
67
67
  - Install development dependencies: `npm install`
68
68
  - Run unit tests: `npm test`
69
69
  - Start test server for browser tests: `npm run integration_test`
70
- - Browse to [http://localhost:3000/tests/](http://localhost:3000/tests/) and choose a scenario to run
70
+ - Browse to [http://localhost:3001/tests/](http://localhost:3001/tests/) and choose a scenario to run
71
71
 
72
72
  In the future we plan to automate the last step with a headless browser to streamline development (although
73
73
  Mixpanel production releases are tested against a large matrix of browsers and operating systems).
package/build.sh CHANGED
@@ -19,15 +19,11 @@ if [ ! -z "$FULL" ]; then
19
19
  npx webpack tests/module-cjs.js tests/module-cjs.bundle.js
20
20
  npx browserify tests/module-es2015.js -t [ babelify --compact false ] --outfile tests/module-es2015.bundle.js
21
21
 
22
- echo 'Bundling module-loader examples'
23
- pushd examples/commonjs-browserify; npm install && npm run build; popd
24
- pushd examples/es2015-babelify; npm install && npm run build; popd
25
- pushd examples/umd-webpack; npm install && npm run build; popd
26
22
  pushd examples/typescript; npm install && npm run build; popd
27
23
  fi
28
24
 
29
25
  if [ ! -z "$DIST" ]; then
30
26
  echo 'Copying to dist/'
31
27
  rm -r dist
32
- cp -r build dist
28
+ rsync -av --exclude='test' build/ dist/
33
29
  fi
@@ -2,10 +2,12 @@ export type Persistence = "cookie" | "localStorage";
2
2
 
3
3
  export type ApiPayloadFormat = "base64" | "json";
4
4
 
5
- export type PushItem = Array<string | Dict>;
5
+ export type PushItem = Array<string | Dict | ((this: Mixpanel) => void)>;
6
6
 
7
7
  export type Query = string | Element | Element[];
8
8
 
9
+ export type RemoteSettingType = "disabled" | "fallback" | "strict";
10
+
9
11
  export interface Dict {
10
12
  [key: string]: any;
11
13
  }
@@ -155,22 +157,32 @@ export interface FlagsConfig {
155
157
  context: Dict;
156
158
  }
157
159
 
160
+ export interface BeforeSendHookPayload {
161
+ event: string;
162
+ properties: Record<string, any>;
163
+ }
164
+
158
165
  export interface Config {
159
166
  api_host: string;
160
167
  api_routes: {
161
168
  track?: string;
162
169
  engage?: string;
163
170
  groups?: string;
171
+ record?: string;
172
+ flags?: string;
164
173
  };
165
174
  api_method: string;
166
175
  api_transport: string;
167
176
  app_host: string;
168
177
  api_payload_format: ApiPayloadFormat;
169
178
  autotrack: boolean;
179
+ batch_autostart: boolean;
180
+ batch_requests: boolean;
170
181
  cdn: string;
171
182
  cookie_domain: string;
172
183
  cross_site_cookie: boolean;
173
184
  cross_subdomain_cookie: boolean;
185
+ error_reporter: (msg: string, err?: Error) => void;
174
186
  flags: boolean | FlagsConfig;
175
187
  persistence: Persistence;
176
188
  persistence_name: string;
@@ -207,24 +219,54 @@ export interface Config {
207
219
  inapp_protocol: string;
208
220
  inapp_link_new_window: boolean;
209
221
  ignore_dnt: boolean;
210
- batch_requests: boolean;
211
222
  batch_size: number;
212
223
  batch_flush_interval_ms: number;
213
224
  batch_request_timeout_ms: number;
225
+ recorder_src: string;
214
226
  record_block_class: string | RegExp;
215
227
  record_block_selector: string;
216
228
  record_collect_fonts: boolean;
217
229
  record_idle_timeout_ms: number;
218
230
  record_inline_images: boolean;
219
231
  record_mask_text_class: string | RegExp;
220
- record_mask_text_selector: string;
232
+ record_mask_text_selector: string | string[];
233
+ record_unmask_text_selector: string | string[];
234
+ record_mask_all_text: boolean;
235
+ record_mask_input_selector: string | string[];
236
+ record_unmask_input_selector: string | string[];
237
+ record_mask_all_inputs: boolean;
221
238
  record_min_ms: number;
222
239
  record_max_ms: number;
223
240
  record_sessions_percent: number;
224
241
  record_canvas: boolean;
225
242
  record_heatmap_data: boolean;
243
+ remote_settings_mode: RemoteSettingType;
244
+ hooks: {
245
+ before_identify?: (new_distinct_id: string) => string | null;
246
+ before_register?: (
247
+ props: Dict,
248
+ days_or_options?: number | Partial<RegisterOptions>
249
+ ) => Dict | Array<Dict | number | Partial<RegisterOptions>> | null;
250
+ before_register_once?: (
251
+ props: Dict,
252
+ default_value?: any,
253
+ days_or_options?: number | Partial<RegisterOptions>
254
+ ) => Dict | Array<any | Dict | number | Partial<RegisterOptions>> | null;
255
+ before_send_events?: (
256
+ event: BeforeSendHookPayload
257
+ ) => BeforeSendHookPayload | null;
258
+ before_track?: (
259
+ event_name: string,
260
+ properties: Dict
261
+ ) => string | Array<string | Dict> | null;
262
+ before_unregister?: (
263
+ property: string,
264
+ options?: Partial<RegisterOptions>
265
+ ) => string | Partial<RegisterOptions> | null;
266
+ };
226
267
  }
227
268
 
269
+
228
270
  export type VerboseResponse =
229
271
  | {
230
272
  status: 1;
@@ -323,10 +365,11 @@ export interface Mixpanel {
323
365
  get_distinct_id(): any;
324
366
  get_group(group_key: string, group_id: string): Group;
325
367
  get_property(property_name: string): any;
368
+ get_session_replay_url(): string;
326
369
  has_opted_in_tracking(options?: Partial<HasOptedInOutOptions>): boolean;
327
370
  has_opted_out_tracking(options?: Partial<HasOptedInOutOptions>): boolean;
328
371
  identify(unique_id?: string): any;
329
- init(token: string, config: Partial<Config>, name: string): Mixpanel;
372
+ init(token: string, config: Partial<Config>, name?: string): Mixpanel;
330
373
  opt_in_tracking(options?: Partial<InTrackingOptions>): void;
331
374
  opt_out_tracking(options?: Partial<OutTrackingOptions>): void;
332
375
  push(item: PushItem): void;
@@ -351,6 +394,7 @@ export interface Mixpanel {
351
394
  group_ids: string | string[] | number | number[],
352
395
  callback?: Callback
353
396
  ): void;
397
+ start_batch_senders(): void;
354
398
  time_event(event_name: string): void;
355
399
  track(
356
400
  event_name: string,
@@ -380,6 +424,7 @@ export interface Mixpanel {
380
424
  ): void;
381
425
  unregister(property: string, options?: Partial<RegisterOptions>): void;
382
426
  people: People;
427
+ start_batch_senders(): void;
383
428
  start_session_recording(): void;
384
429
  stop_session_recording(): void;
385
430
  get_session_recording_properties(): { $mp_replay_id?: string } | {};