posthog-js 1.288.1 → 1.290.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/dist/array.full.es5.js +1 -1
  2. package/dist/array.full.es5.js.map +1 -1
  3. package/dist/array.full.js +1 -1
  4. package/dist/array.full.js.map +1 -1
  5. package/dist/array.full.no-external.js +1 -1
  6. package/dist/array.full.no-external.js.map +1 -1
  7. package/dist/array.js +1 -1
  8. package/dist/array.js.map +1 -1
  9. package/dist/array.no-external.js +1 -1
  10. package/dist/array.no-external.js.map +1 -1
  11. package/dist/customizations.full.js +1 -1
  12. package/dist/lazy-recorder.js +1 -1
  13. package/dist/main.js +1 -1
  14. package/dist/main.js.map +1 -1
  15. package/dist/module.d.ts +17 -0
  16. package/dist/module.full.d.ts +17 -0
  17. package/dist/module.full.js +1 -1
  18. package/dist/module.full.js.map +1 -1
  19. package/dist/module.full.no-external.d.ts +17 -0
  20. package/dist/module.full.no-external.js +1 -1
  21. package/dist/module.full.no-external.js.map +1 -1
  22. package/dist/module.js +1 -1
  23. package/dist/module.js.map +1 -1
  24. package/dist/module.no-external.d.ts +17 -0
  25. package/dist/module.no-external.js +1 -1
  26. package/dist/module.no-external.js.map +1 -1
  27. package/dist/posthog-recorder.js +1 -1
  28. package/dist/src/posthog-core.d.ts +3 -0
  29. package/dist/src/types.d.ts +14 -0
  30. package/dist/surveys-preview.d.ts +17 -0
  31. package/lib/package.json +1 -1
  32. package/lib/src/entrypoints/array.full.es5.js +9 -0
  33. package/lib/src/entrypoints/array.full.es5.js.map +1 -1
  34. package/lib/src/posthog-core.d.ts +3 -0
  35. package/lib/src/posthog-core.js +129 -27
  36. package/lib/src/posthog-core.js.map +1 -1
  37. package/lib/src/types.d.ts +14 -0
  38. package/lib/src/types.js.map +1 -1
  39. package/package.json +1 -1
  40. package/react/dist/esm/index.js +42 -24
  41. package/react/dist/esm/index.js.map +1 -1
  42. package/react/dist/types/index.d.ts +5 -2
  43. package/react/dist/umd/index.js +42 -24
  44. package/react/dist/umd/index.js.map +1 -1
@@ -82,6 +82,7 @@ export declare class PostHog {
82
82
  _triggered_notifs: any;
83
83
  compression?: Compression;
84
84
  __request_queue: QueuedRequestWithOptions[];
85
+ _pendingRemoteConfig?: RemoteConfig;
85
86
  analyticsDefaultEndpoint: string;
86
87
  version: string;
87
88
  _initialPersonProfilesConfig: 'always' | 'never' | 'identified_only' | null;
@@ -132,6 +133,8 @@ export declare class PostHog {
132
133
  */
133
134
  init(token: string, config?: OnlyValidKeys<Partial<PostHogConfig>, Partial<PostHogConfig>>, name?: string): PostHog;
134
135
  _init(token: string, config?: Partial<PostHogConfig>, name?: string): PostHog;
136
+ private _initExtensions;
137
+ private _processInitTaskQueue;
135
138
  _onRemoteConfig(config: RemoteConfig): void;
136
139
  _loaded(): void;
137
140
  _start_queue_if_opted_in(): void;
@@ -566,6 +566,20 @@ export interface PostHogConfig {
566
566
  * @default 'unset'
567
567
  */
568
568
  defaults: ConfigDefaults;
569
+ /**
570
+ * EXPERIMENTAL: Defers initialization of non-critical extensions (autocapture, session recording, etc.)
571
+ * to the next event loop tick using setTimeout. This reduces main thread blocking during SDK
572
+ * initialization for better page load performance, while keeping critical functionality
573
+ * (persistence, sessions, capture) available immediately.
574
+ *
575
+ * When enabled:
576
+ * - Persistence, sessions, and basic capture work immediately
577
+ * - Extensions (autocapture, recording, heatmaps, etc.) start after yielding back to the browser
578
+ *
579
+ * @default false (will be true for defaults >= '2025-11-06' in the future)
580
+ * @experimental
581
+ */
582
+ __preview_deferred_init_extensions: boolean;
569
583
  /**
570
584
  * Determines the session recording options.
571
585
  *
@@ -1363,6 +1363,20 @@ interface PostHogConfig {
1363
1363
  * @default 'unset'
1364
1364
  */
1365
1365
  defaults: ConfigDefaults;
1366
+ /**
1367
+ * EXPERIMENTAL: Defers initialization of non-critical extensions (autocapture, session recording, etc.)
1368
+ * to the next event loop tick using setTimeout. This reduces main thread blocking during SDK
1369
+ * initialization for better page load performance, while keeping critical functionality
1370
+ * (persistence, sessions, capture) available immediately.
1371
+ *
1372
+ * When enabled:
1373
+ * - Persistence, sessions, and basic capture work immediately
1374
+ * - Extensions (autocapture, recording, heatmaps, etc.) start after yielding back to the browser
1375
+ *
1376
+ * @default false (will be true for defaults >= '2025-11-06' in the future)
1377
+ * @experimental
1378
+ */
1379
+ __preview_deferred_init_extensions: boolean;
1366
1380
  /**
1367
1381
  * Determines the session recording options.
1368
1382
  *
@@ -3231,6 +3245,7 @@ declare class PostHog {
3231
3245
  _triggered_notifs: any;
3232
3246
  compression?: Compression;
3233
3247
  __request_queue: QueuedRequestWithOptions[];
3248
+ _pendingRemoteConfig?: RemoteConfig;
3234
3249
  analyticsDefaultEndpoint: string;
3235
3250
  version: string;
3236
3251
  _initialPersonProfilesConfig: 'always' | 'never' | 'identified_only' | null;
@@ -3281,6 +3296,8 @@ declare class PostHog {
3281
3296
  */
3282
3297
  init(token: string, config?: OnlyValidKeys<Partial<PostHogConfig>, Partial<PostHogConfig>>, name?: string): PostHog;
3283
3298
  _init(token: string, config?: Partial<PostHogConfig>, name?: string): PostHog;
3299
+ private _initExtensions;
3300
+ private _processInitTaskQueue;
3284
3301
  _onRemoteConfig(config: RemoteConfig): void;
3285
3302
  _loaded(): void;
3286
3303
  _start_queue_if_opted_in(): void;
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthog-js",
3
- "version": "1.288.1",
3
+ "version": "1.290.0",
4
4
  "description": "Posthog-js allows you to automatically capture usage and send events to PostHog.",
5
5
  "repository": "https://github.com/PostHog/posthog-js",
6
6
  "author": "hey@posthog.com",
@@ -7,6 +7,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  // and it doesn't include "web-vitals" which doesn't support IE11
8
8
  require("core-js/features/object/entries");
9
9
  require("core-js/features/object/from-entries");
10
+ if (typeof performance === 'undefined' || typeof performance.now !== 'function') {
11
+ var perf = typeof performance !== 'undefined' ? performance : {};
12
+ perf.now = perf.now || (function () { return Date.now(); });
13
+ if (typeof performance === 'undefined') {
14
+ // eslint-disable-next-line no-restricted-globals
15
+ ;
16
+ window.performance = perf;
17
+ }
18
+ }
10
19
  require("./surveys");
11
20
  require("./exception-autocapture");
12
21
  require("./tracing-headers");
@@ -1 +1 @@
1
- {"version":3,"file":"array.full.es5.js","sourceRoot":"","sources":["../../../src/entrypoints/array.full.es5.ts"],"names":[],"mappings":";AAAA,mDAAmD;AACnD,4DAA4D;AAC5D,4BAA4B;;AAE5B,0DAA0D;AAC1D,iEAAiE;AAEjE,2CAAwC;AACxC,gDAA6C;AAE7C,qBAAkB;AAClB,mCAAgC;AAChC,6BAA0B;AAC1B,+BAA4B","sourcesContent":["// a straight copy of the array.full.ts entrypoint,\n// but will have different config when passed through rollup\n// to allow es5/IE11 support\n\n// it doesn't include recorder which doesn't support IE11,\n// and it doesn't include \"web-vitals\" which doesn't support IE11\n\nimport 'core-js/features/object/entries'\nimport 'core-js/features/object/from-entries'\n\nimport './surveys'\nimport './exception-autocapture'\nimport './tracing-headers'\nimport './array.no-external'\n"]}
1
+ {"version":3,"file":"array.full.es5.js","sourceRoot":"","sources":["../../../src/entrypoints/array.full.es5.ts"],"names":[],"mappings":";AAAA,mDAAmD;AACnD,4DAA4D;AAC5D,4BAA4B;;AAE5B,0DAA0D;AAC1D,iEAAiE;AAEjE,2CAAwC;AACxC,gDAA6C;AAE7C,IAAI,OAAO,WAAW,KAAK,WAAW,IAAI,OAAO,WAAW,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;IAC9E,IAAM,IAAI,GAAG,OAAO,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAE,EAAU,CAAA;IAC3E,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,cAAM,OAAA,IAAI,CAAC,GAAG,EAAE,EAAV,CAAU,CAAC,CAAA;IACzC,IAAI,OAAO,WAAW,KAAK,WAAW,EAAE,CAAC;QACrC,iDAAiD;QACjD,CAAC;QAAC,MAAc,CAAC,WAAW,GAAG,IAAI,CAAA;IACvC,CAAC;AACL,CAAC;AAED,qBAAkB;AAClB,mCAAgC;AAChC,6BAA0B;AAC1B,+BAA4B","sourcesContent":["// a straight copy of the array.full.ts entrypoint,\n// but will have different config when passed through rollup\n// to allow es5/IE11 support\n\n// it doesn't include recorder which doesn't support IE11,\n// and it doesn't include \"web-vitals\" which doesn't support IE11\n\nimport 'core-js/features/object/entries'\nimport 'core-js/features/object/from-entries'\n\nif (typeof performance === 'undefined' || typeof performance.now !== 'function') {\n const perf = typeof performance !== 'undefined' ? performance : ({} as any)\n perf.now = perf.now || (() => Date.now())\n if (typeof performance === 'undefined') {\n // eslint-disable-next-line no-restricted-globals\n ;(window as any).performance = perf\n }\n}\n\nimport './surveys'\nimport './exception-autocapture'\nimport './tracing-headers'\nimport './array.no-external'\n"]}
@@ -82,6 +82,7 @@ export declare class PostHog {
82
82
  _triggered_notifs: any;
83
83
  compression?: Compression;
84
84
  __request_queue: QueuedRequestWithOptions[];
85
+ _pendingRemoteConfig?: RemoteConfig;
85
86
  analyticsDefaultEndpoint: string;
86
87
  version: string;
87
88
  _initialPersonProfilesConfig: 'always' | 'never' | 'identified_only' | null;
@@ -132,6 +133,8 @@ export declare class PostHog {
132
133
  */
133
134
  init(token: string, config?: OnlyValidKeys<Partial<PostHogConfig>, Partial<PostHogConfig>>, name?: string): PostHog;
134
135
  _init(token: string, config?: Partial<PostHogConfig>, name?: string): PostHog;
136
+ private _initExtensions;
137
+ private _processInitTaskQueue;
135
138
  _onRemoteConfig(config: RemoteConfig): void;
136
139
  _loaded(): void;
137
140
  _start_queue_if_opted_in(): void;
@@ -133,6 +133,7 @@ var defaultConfig = function (defaults) {
133
133
  capture_pageview: defaults === '2025-05-24' ? 'history_change' : true,
134
134
  capture_pageleave: 'if_capture_pageview', // We'll only capture pageleave events if capture_pageview is also true
135
135
  defaults: defaults !== null && defaults !== void 0 ? defaults : 'unset',
136
+ __preview_deferred_init_extensions: false, // Opt-in only for now
136
137
  debug: (globals_1.location && (0, core_1.isString)(globals_1.location === null || globals_1.location === void 0 ? void 0 : globals_1.location.search) && globals_1.location.search.indexOf('__posthog_debug=true') !== -1) || false,
137
138
  cookie_expiration: 365,
138
139
  upgrade: false,
@@ -388,7 +389,7 @@ var PostHog = /** @class */ (function () {
388
389
  //
389
390
  PostHog.prototype._init = function (token, config, name) {
390
391
  var _this = this;
391
- var _a, _b, _c, _d, _e, _f;
392
+ var _a, _b, _c, _d, _e;
392
393
  if (config === void 0) { config = {}; }
393
394
  if ((0, core_1.isUndefined)(token) || (0, core_1.isEmptyString)(token)) {
394
395
  logger_1.logger.critical('PostHog was initialized without a token. This likely indicates a misconfiguration. Please check the first argument passed to posthog.init()');
@@ -435,28 +436,21 @@ var PostHog = /** @class */ (function () {
435
436
  this.sessionManager = new sessionid_1.SessionIdManager(this);
436
437
  this.sessionPropsManager = new session_props_1.SessionPropsManager(this, this.sessionManager, this.persistence);
437
438
  }
438
- new tracing_headers_1.TracingHeaders(this).startIfEnabledOrStop();
439
- this.siteApps = new site_apps_1.SiteApps(this);
440
- (_a = this.siteApps) === null || _a === void 0 ? void 0 : _a.init();
441
- if (!startInCookielessMode) {
442
- this.sessionRecording = new session_recording_1.SessionRecording(this);
443
- this.sessionRecording.startIfEnabledOrStop();
439
+ // Conditionally defer extension initialization based on config
440
+ if (this.config.__preview_deferred_init_extensions) {
441
+ // EXPERIMENTAL: Defer non-critical extension initialization to next tick
442
+ // This reduces main thread blocking during init
443
+ // while keeping critical path (persistence, sessions, capture) synchronous
444
+ logger_1.logger.info('Deferring extension initialization to improve startup performance');
445
+ setTimeout(function () {
446
+ _this._initExtensions(startInCookielessMode);
447
+ }, 0);
448
+ }
449
+ else {
450
+ // Legacy synchronous initialization (default for now)
451
+ logger_1.logger.info('Initializing extensions synchronously');
452
+ this._initExtensions(startInCookielessMode);
444
453
  }
445
- if (!this.config.disable_scroll_properties) {
446
- this.scrollManager.startMeasuringScrollPosition();
447
- }
448
- this.autocapture = new autocapture_1.Autocapture(this);
449
- this.autocapture.startIfEnabled();
450
- this.surveys.loadIfEnabled();
451
- this.heatmaps = new heatmaps_1.Heatmaps(this);
452
- this.heatmaps.startIfEnabled();
453
- this.webVitalsAutocapture = new web_vitals_1.WebVitalsAutocapture(this);
454
- this.exceptionObserver = new exception_autocapture_1.ExceptionObserver(this);
455
- this.exceptionObserver.startIfEnabled();
456
- this.deadClicksAutocapture = new dead_clicks_autocapture_1.DeadClicksAutocapture(this, dead_clicks_autocapture_1.isDeadClicksEnabledForAutocapture);
457
- this.deadClicksAutocapture.startIfEnabled();
458
- this.historyAutocapture = new history_autocapture_1.HistoryAutocapture(this);
459
- this.historyAutocapture.startIfEnabled();
460
454
  // if any instance on the page has debug = true, we set the
461
455
  // global debug to be true
462
456
  config_1.default.DEBUG = config_1.default.DEBUG || this.config.debug;
@@ -471,23 +465,23 @@ var PostHog = /** @class */ (function () {
471
465
  }
472
466
  // isUndefined doesn't provide typehint here so wouldn't reduce bundle as we'd need to assign
473
467
  // eslint-disable-next-line posthog-js/no-direct-undefined-check
474
- if (((_b = config.bootstrap) === null || _b === void 0 ? void 0 : _b.distinctID) !== undefined) {
468
+ if (((_a = config.bootstrap) === null || _a === void 0 ? void 0 : _a.distinctID) !== undefined) {
475
469
  var uuid = this.config.get_device_id((0, uuidv7_1.uuidv7)());
476
- var deviceID = ((_c = config.bootstrap) === null || _c === void 0 ? void 0 : _c.isIdentifiedID) ? uuid : config.bootstrap.distinctID;
477
- this.persistence.set_property(constants_1.USER_STATE, ((_d = config.bootstrap) === null || _d === void 0 ? void 0 : _d.isIdentifiedID) ? 'identified' : 'anonymous');
470
+ var deviceID = ((_b = config.bootstrap) === null || _b === void 0 ? void 0 : _b.isIdentifiedID) ? uuid : config.bootstrap.distinctID;
471
+ this.persistence.set_property(constants_1.USER_STATE, ((_c = config.bootstrap) === null || _c === void 0 ? void 0 : _c.isIdentifiedID) ? 'identified' : 'anonymous');
478
472
  this.register({
479
473
  distinct_id: config.bootstrap.distinctID,
480
474
  $device_id: deviceID,
481
475
  });
482
476
  }
483
477
  if (this._hasBootstrappedFeatureFlags()) {
484
- var activeFlags_1 = Object.keys(((_e = config.bootstrap) === null || _e === void 0 ? void 0 : _e.featureFlags) || {})
478
+ var activeFlags_1 = Object.keys(((_d = config.bootstrap) === null || _d === void 0 ? void 0 : _d.featureFlags) || {})
485
479
  .filter(function (flag) { var _a, _b; return !!((_b = (_a = config.bootstrap) === null || _a === void 0 ? void 0 : _a.featureFlags) === null || _b === void 0 ? void 0 : _b[flag]); })
486
480
  .reduce(function (res, key) {
487
481
  var _a, _b;
488
482
  return ((res[key] = ((_b = (_a = config.bootstrap) === null || _a === void 0 ? void 0 : _a.featureFlags) === null || _b === void 0 ? void 0 : _b[key]) || false), res);
489
483
  }, {});
490
- var featureFlagPayloads = Object.keys(((_f = config.bootstrap) === null || _f === void 0 ? void 0 : _f.featureFlagPayloads) || {})
484
+ var featureFlagPayloads = Object.keys(((_e = config.bootstrap) === null || _e === void 0 ? void 0 : _e.featureFlagPayloads) || {})
491
485
  .filter(function (key) { return activeFlags_1[key]; })
492
486
  .reduce(function (res, key) {
493
487
  var _a, _b, _c, _d;
@@ -540,6 +534,110 @@ var PostHog = /** @class */ (function () {
540
534
  }
541
535
  return this;
542
536
  };
537
+ PostHog.prototype._initExtensions = function (startInCookielessMode) {
538
+ var _this = this;
539
+ // we don't support IE11 anymore, so performance.now is safe
540
+ // eslint-disable-next-line compat/compat
541
+ var initStartTime = performance.now();
542
+ this.historyAutocapture = new history_autocapture_1.HistoryAutocapture(this);
543
+ this.historyAutocapture.startIfEnabled();
544
+ // Build queue of extension initialization tasks
545
+ var initTasks = [];
546
+ initTasks.push(function () {
547
+ new tracing_headers_1.TracingHeaders(_this).startIfEnabledOrStop();
548
+ });
549
+ initTasks.push(function () {
550
+ var _a;
551
+ _this.siteApps = new site_apps_1.SiteApps(_this);
552
+ (_a = _this.siteApps) === null || _a === void 0 ? void 0 : _a.init();
553
+ });
554
+ if (!startInCookielessMode) {
555
+ initTasks.push(function () {
556
+ _this.sessionRecording = new session_recording_1.SessionRecording(_this);
557
+ _this.sessionRecording.startIfEnabledOrStop();
558
+ });
559
+ }
560
+ if (!this.config.disable_scroll_properties) {
561
+ initTasks.push(function () {
562
+ _this.scrollManager.startMeasuringScrollPosition();
563
+ });
564
+ }
565
+ initTasks.push(function () {
566
+ _this.autocapture = new autocapture_1.Autocapture(_this);
567
+ _this.autocapture.startIfEnabled();
568
+ });
569
+ initTasks.push(function () {
570
+ _this.surveys.loadIfEnabled();
571
+ });
572
+ initTasks.push(function () {
573
+ _this.heatmaps = new heatmaps_1.Heatmaps(_this);
574
+ _this.heatmaps.startIfEnabled();
575
+ });
576
+ initTasks.push(function () {
577
+ _this.webVitalsAutocapture = new web_vitals_1.WebVitalsAutocapture(_this);
578
+ });
579
+ initTasks.push(function () {
580
+ _this.exceptionObserver = new exception_autocapture_1.ExceptionObserver(_this);
581
+ _this.exceptionObserver.startIfEnabled();
582
+ });
583
+ initTasks.push(function () {
584
+ _this.deadClicksAutocapture = new dead_clicks_autocapture_1.DeadClicksAutocapture(_this, dead_clicks_autocapture_1.isDeadClicksEnabledForAutocapture);
585
+ _this.deadClicksAutocapture.startIfEnabled();
586
+ });
587
+ // Replay any pending remote config that arrived before extensions were ready
588
+ initTasks.push(function () {
589
+ if (_this._pendingRemoteConfig) {
590
+ var config = _this._pendingRemoteConfig;
591
+ _this._pendingRemoteConfig = undefined; // Clear before replaying to avoid re-storing
592
+ _this._onRemoteConfig(config);
593
+ }
594
+ });
595
+ // Process tasks with time-slicing to avoid blocking
596
+ this._processInitTaskQueue(initTasks, initStartTime);
597
+ };
598
+ PostHog.prototype._processInitTaskQueue = function (queue, initStartTime) {
599
+ var _this = this;
600
+ var TIME_BUDGET_MS = 30; // Respect frame budget (~60fps = 16ms, but we're already deferred)
601
+ while (queue.length > 0) {
602
+ // Only time-slice if deferred init is enabled, otherwise run synchronously
603
+ if (this.config.__preview_deferred_init_extensions) {
604
+ // we don't support IE11 anymore, so performance.now is safe
605
+ // eslint-disable-next-line compat/compat
606
+ var elapsed = performance.now() - initStartTime;
607
+ // Check if we've exceeded our time budget
608
+ if (elapsed >= TIME_BUDGET_MS && queue.length > 0) {
609
+ // Yield to browser, then continue processing
610
+ setTimeout(function () {
611
+ _this._processInitTaskQueue(queue, initStartTime);
612
+ }, 0);
613
+ return;
614
+ }
615
+ }
616
+ // Process next task
617
+ var task = queue.shift();
618
+ if (task) {
619
+ try {
620
+ task();
621
+ }
622
+ catch (error) {
623
+ logger_1.logger.error('Error initializing extension:', error);
624
+ }
625
+ }
626
+ }
627
+ // All tasks complete - record timing for both sync and deferred modes
628
+ // we don't support IE11 anymore, so performance.now is safe
629
+ // eslint-disable-next-line compat/compat
630
+ var taskInitTiming = Math.round(performance.now() - initStartTime);
631
+ this.register_for_session({
632
+ $sdk_debug_extensions_init_method: this.config.__preview_deferred_init_extensions
633
+ ? 'deferred'
634
+ : 'synchronous',
635
+ $sdk_debug_extensions_init_time_ms: taskInitTiming,
636
+ });
637
+ if (this.config.__preview_deferred_init_extensions) {
638
+ logger_1.logger.info("PostHog extensions initialized (".concat(taskInitTiming, "ms)"));
639
+ }
640
+ };
543
641
  PostHog.prototype._onRemoteConfig = function (config) {
544
642
  var _this = this;
545
643
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -550,6 +648,10 @@ var PostHog = /** @class */ (function () {
550
648
  }, 500);
551
649
  return;
552
650
  }
651
+ // Store config in case extensions aren't initialized yet (only needed for deferred init)
652
+ if (this.config.__preview_deferred_init_extensions) {
653
+ this._pendingRemoteConfig = config;
654
+ }
553
655
  this.compression = undefined;
554
656
  if (config.supportedCompression && !this.config.disable_compression) {
555
657
  this.compression = (0, core_1.includes)(config['supportedCompression'], types_1.Compression.GZipJS)