swetrix 4.2.0 → 4.3.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.
@@ -88,11 +88,29 @@ const getPath = (options) => {
88
88
  return result;
89
89
  };
90
90
 
91
+ const SESSION_REPLAY_PRIVACY_VALUES = ['total', 'normal', 'none'];
91
92
  const defaultActions = {
92
93
  stop() { },
93
94
  };
95
+ const defaultSessionReplayActions = {
96
+ async stop() { },
97
+ async flush() { },
98
+ };
94
99
  const DEFAULT_API_HOST = 'https://api.swetrix.com/log';
95
100
  const DEFAULT_API_BASE = 'https://api.swetrix.com';
101
+ const DEFAULT_RRWEB_FILE = 'replaylibrary.min.js';
102
+ const DEFAULT_RRWEB_URL = `https://cdn.jsdelivr.net/npm/swetrix@latest/dist/${DEFAULT_RRWEB_FILE}`;
103
+ const DEFAULT_SESSION_REPLAY_FLUSH_INTERVAL = 5000;
104
+ const DEFAULT_SESSION_REPLAY_MAX_EVENTS = 100;
105
+ const DEFAULT_SESSION_REPLAY_PRIVACY = 'total';
106
+ const SESSION_REPLAY_ACTIVITY_EVENTS = [
107
+ 'click',
108
+ 'keydown',
109
+ 'mousedown',
110
+ 'mousemove',
111
+ 'scroll',
112
+ 'touchstart',
113
+ ];
96
114
  // Default cache duration: 5 minutes
97
115
  const DEFAULT_CACHE_DURATION = 5 * 60 * 1000;
98
116
  class Lib {
@@ -106,9 +124,15 @@ class Lib {
106
124
  this.activePage = null;
107
125
  this.errorListenerExists = false;
108
126
  this.cachedData = null;
127
+ this.rrwebLoader = null;
128
+ this.sessionReplayActions = null;
129
+ this.sessionReplayInitPromise = null;
109
130
  this.trackPathChange = this.trackPathChange.bind(this);
110
131
  this.heartbeat = this.heartbeat.bind(this);
111
132
  this.captureError = this.captureError.bind(this);
133
+ if (this.getSessionReplayPreloadOption()) {
134
+ void this.preloadSessionReplay().catch(() => undefined);
135
+ }
112
136
  }
113
137
  captureError(event) {
114
138
  var _a, _b, _c, _d;
@@ -256,10 +280,10 @@ class Lib {
256
280
  };
257
281
  }
258
282
  /**
259
- * Fetches all feature flags and experiments for the project.
260
- * Results are cached for 5 minutes by default.
283
+ * Fetches all feature flags for the project.
284
+ * Results are cached for 5 minutes by default and share a cache with experiments.
261
285
  *
262
- * @param options - Options for evaluating feature flags.
286
+ * @param options - Options for evaluating feature flags (`profileId` only).
263
287
  * @param forceRefresh - If true, bypasses the cache and fetches fresh data.
264
288
  * @returns A promise that resolves to a record of flag keys to boolean values.
265
289
  */
@@ -326,8 +350,8 @@ class Lib {
326
350
  * Gets the value of a single feature flag.
327
351
  *
328
352
  * @param key - The feature flag key.
329
- * @param options - Options for evaluating the feature flag.
330
- * @param defaultValue - Default value to return if the flag is not found. Defaults to false.
353
+ * @param options - Options for evaluating the feature flag (`profileId` only).
354
+ * @param defaultValue - Optional default value to return if the flag is not found. Defaults to false.
331
355
  * @returns A promise that resolves to the boolean value of the flag.
332
356
  */
333
357
  async getFeatureFlag(key, options, defaultValue = false) {
@@ -342,16 +366,16 @@ class Lib {
342
366
  this.cachedData = null;
343
367
  }
344
368
  /**
345
- * Fetches all A/B test experiments for the project.
369
+ * Fetches variant assignments for running A/B test experiments returned by feature flag evaluation.
346
370
  * Results are cached for 5 minutes by default (shared cache with feature flags).
347
371
  *
348
- * @param options - Options for evaluating experiments.
372
+ * @param options - Options for evaluating experiments (`profileId` only).
349
373
  * @param forceRefresh - If true, bypasses the cache and fetches fresh data.
350
374
  * @returns A promise that resolves to a record of experiment IDs to variant keys.
351
375
  *
352
376
  * @example
353
377
  * ```typescript
354
- * const experiments = await getExperiments()
378
+ * const experiments = await getExperiments({ profileId: 'user-123' })
355
379
  * // experiments = { 'exp-123': 'variant-a', 'exp-456': 'control' }
356
380
  * ```
357
381
  */
@@ -382,13 +406,16 @@ class Lib {
382
406
  * Gets the variant key for a specific A/B test experiment.
383
407
  *
384
408
  * @param experimentId - The experiment ID.
385
- * @param options - Options for evaluating the experiment.
386
- * @param defaultVariant - Default variant key to return if the experiment is not found. Defaults to null.
409
+ * @param options - Options for evaluating the experiment (`profileId` only).
410
+ * @param defaultVariant - Optional default variant key to return if the experiment is not found. Defaults to null.
387
411
  * @returns A promise that resolves to the variant key assigned to this user, or defaultVariant if not found.
388
412
  *
389
413
  * @example
390
414
  * ```typescript
391
- * const variant = await getExperiment('checkout-redesign')
415
+ * const variant = await getExperiment('checkout-redesign', { profileId: 'user-123' })
416
+ *
417
+ * // Optional fallback variant:
418
+ * const variantWithFallback = await getExperiment('checkout-redesign', undefined, 'control')
392
419
  *
393
420
  * if (variant === 'new-checkout') {
394
421
  * // Show new checkout flow
@@ -504,6 +531,167 @@ class Lib {
504
531
  return null;
505
532
  }
506
533
  }
534
+ async startSessionReplay(options = {}) {
535
+ if (this.sessionReplayActions) {
536
+ return this.sessionReplayActions;
537
+ }
538
+ if (this.sessionReplayInitPromise) {
539
+ return this.sessionReplayInitPromise;
540
+ }
541
+ const initPromise = this.initialiseSessionReplay(options);
542
+ this.sessionReplayInitPromise = initPromise;
543
+ try {
544
+ return await initPromise;
545
+ }
546
+ finally {
547
+ if (this.sessionReplayInitPromise === initPromise) {
548
+ this.sessionReplayInitPromise = null;
549
+ }
550
+ }
551
+ }
552
+ async initialiseSessionReplay(options) {
553
+ var _a;
554
+ if (this.sessionReplayActions) {
555
+ return this.sessionReplayActions;
556
+ }
557
+ if (!this.canTrack()) {
558
+ return defaultSessionReplayActions;
559
+ }
560
+ if (!this.shouldSampleSessionReplay(options.sampleRate)) {
561
+ return defaultSessionReplayActions;
562
+ }
563
+ try {
564
+ await this.preloadSessionReplay();
565
+ }
566
+ catch (_b) {
567
+ return defaultSessionReplayActions;
568
+ }
569
+ const rrweb = window.rrweb;
570
+ if (!(rrweb === null || rrweb === void 0 ? void 0 : rrweb.record)) {
571
+ return defaultSessionReplayActions;
572
+ }
573
+ const privacy = this.getSessionReplayPrivacy(options.privacy);
574
+ const replayId = this.createReplayId();
575
+ const started = await this.sendSessionReplayStart(replayId, privacy);
576
+ if (!started) {
577
+ return defaultSessionReplayActions;
578
+ }
579
+ const flushIntervalMs = typeof options.flushIntervalMs === 'number' && options.flushIntervalMs > 0
580
+ ? options.flushIntervalMs
581
+ : DEFAULT_SESSION_REPLAY_FLUSH_INTERVAL;
582
+ const maxEventsPerChunk = typeof options.maxEventsPerChunk === 'number' &&
583
+ options.maxEventsPerChunk > 0
584
+ ? Math.floor(options.maxEventsPerChunk)
585
+ : DEFAULT_SESSION_REPLAY_MAX_EVENTS;
586
+ const maxDurationMs = typeof options.maxDurationMs === 'number' && options.maxDurationMs > 0
587
+ ? options.maxDurationMs
588
+ : null;
589
+ const idleTimeoutMs = typeof options.idleTimeoutMs === 'number' && options.idleTimeoutMs > 0
590
+ ? options.idleTimeoutMs
591
+ : null;
592
+ let chunkIndex = 0;
593
+ let stopped = false;
594
+ let events = [];
595
+ let flushing = Promise.resolve();
596
+ let maxDurationTimer;
597
+ let idleTimer;
598
+ const flush = async (useBeacon = false) => {
599
+ if (!events.length)
600
+ return;
601
+ const chunk = events;
602
+ events = [];
603
+ const currentChunkIndex = chunkIndex++;
604
+ flushing = flushing
605
+ .catch(() => undefined)
606
+ .then(() => this.sendSessionReplayChunk(replayId, privacy, currentChunkIndex, chunk, useBeacon));
607
+ await flushing;
608
+ };
609
+ const userEmit = (_a = options.rrweb) === null || _a === void 0 ? void 0 : _a.emit;
610
+ const recordOptions = this.getSessionReplayRecordOptions(privacy, options.rrweb, (event) => {
611
+ try {
612
+ userEmit === null || userEmit === void 0 ? void 0 : userEmit(event);
613
+ }
614
+ catch (_a) { }
615
+ events.push(event);
616
+ if (events.length >= maxEventsPerChunk) {
617
+ void flush();
618
+ }
619
+ });
620
+ const stopRecording = rrweb.record(recordOptions);
621
+ const timer = setInterval(() => void flush(), flushIntervalMs);
622
+ const flushOnPageExit = () => void flush(true);
623
+ const flushOnHidden = () => {
624
+ if (document.visibilityState === 'hidden') {
625
+ void flush(true);
626
+ }
627
+ };
628
+ const clearIdleTimer = () => {
629
+ if (idleTimer) {
630
+ clearTimeout(idleTimer);
631
+ idleTimer = undefined;
632
+ }
633
+ };
634
+ const stopSessionReplay = async () => {
635
+ if (stopped)
636
+ return;
637
+ stopped = true;
638
+ clearInterval(timer);
639
+ if (maxDurationTimer) {
640
+ clearTimeout(maxDurationTimer);
641
+ }
642
+ clearIdleTimer();
643
+ window.removeEventListener('pagehide', flushOnPageExit);
644
+ document.removeEventListener('visibilitychange', flushOnHidden);
645
+ SESSION_REPLAY_ACTIVITY_EVENTS.forEach((eventName) => {
646
+ window.removeEventListener(eventName, resetIdleTimer);
647
+ });
648
+ stopRecording === null || stopRecording === void 0 ? void 0 : stopRecording();
649
+ await flush();
650
+ this.sessionReplayActions = null;
651
+ this.sessionReplayInitPromise = null;
652
+ };
653
+ const resetIdleTimer = () => {
654
+ if (!idleTimeoutMs || stopped)
655
+ return;
656
+ clearIdleTimer();
657
+ idleTimer = setTimeout(() => void stopSessionReplay(), idleTimeoutMs);
658
+ };
659
+ window.addEventListener('pagehide', flushOnPageExit);
660
+ document.addEventListener('visibilitychange', flushOnHidden);
661
+ if (maxDurationMs) {
662
+ maxDurationTimer = setTimeout(() => void stopSessionReplay(), maxDurationMs);
663
+ }
664
+ if (idleTimeoutMs) {
665
+ SESSION_REPLAY_ACTIVITY_EVENTS.forEach((eventName) => {
666
+ window.addEventListener(eventName, resetIdleTimer, { passive: true });
667
+ });
668
+ resetIdleTimer();
669
+ }
670
+ this.sessionReplayActions = {
671
+ stop: stopSessionReplay,
672
+ flush: async () => {
673
+ await flush();
674
+ },
675
+ };
676
+ return this.sessionReplayActions;
677
+ }
678
+ shouldSampleSessionReplay(sampleRate) {
679
+ if (typeof sampleRate !== 'number') {
680
+ return true;
681
+ }
682
+ if (sampleRate <= 0) {
683
+ return false;
684
+ }
685
+ if (sampleRate >= 1) {
686
+ return true;
687
+ }
688
+ return Math.random() < sampleRate;
689
+ }
690
+ getSessionReplayPrivacy(privacy) {
691
+ return SESSION_REPLAY_PRIVACY_VALUES.includes(privacy)
692
+ ? privacy
693
+ : DEFAULT_SESSION_REPLAY_PRIVACY;
694
+ }
507
695
  /**
508
696
  * Gets the API base URL (without /log suffix).
509
697
  */
@@ -593,6 +781,225 @@ class Lib {
593
781
  }
594
782
  return true;
595
783
  }
784
+ getSessionReplayUrl() {
785
+ const replayOption = this.getSessionReplayPreloadOption();
786
+ if (replayOption &&
787
+ typeof replayOption === 'object' &&
788
+ replayOption.rrwebUrl) {
789
+ return replayOption.rrwebUrl;
790
+ }
791
+ return this.getDefaultSessionReplayUrl();
792
+ }
793
+ getSessionReplayPreloadOption() {
794
+ var _a;
795
+ return (_a = this.options) === null || _a === void 0 ? void 0 : _a.preloadSessionReplay;
796
+ }
797
+ getDefaultSessionReplayUrl() {
798
+ if (!isInBrowser()) {
799
+ return DEFAULT_RRWEB_URL;
800
+ }
801
+ const trackerScript = this.getTrackerScript();
802
+ if (trackerScript === null || trackerScript === void 0 ? void 0 : trackerScript.src) {
803
+ const { hostname, pathname } = new URL(trackerScript.src);
804
+ if (hostname === 'swetrix.org' &&
805
+ /^\/swetrix(\.min)?\.js$/i.test(pathname)) {
806
+ return DEFAULT_RRWEB_URL;
807
+ }
808
+ return new URL(DEFAULT_RRWEB_FILE, trackerScript.src).toString();
809
+ }
810
+ return DEFAULT_RRWEB_URL;
811
+ }
812
+ getTrackerScript() {
813
+ const trackerScript = Array.from(document.scripts).find((script) => {
814
+ if (!script.src) {
815
+ return false;
816
+ }
817
+ try {
818
+ const { pathname } = new URL(script.src);
819
+ return /(^|\/)swetrix(\.min)?\.js$/i.test(pathname);
820
+ }
821
+ catch (_a) {
822
+ return false;
823
+ }
824
+ });
825
+ return trackerScript;
826
+ }
827
+ preloadSessionReplay() {
828
+ var _a;
829
+ if (!isInBrowser()) {
830
+ return Promise.resolve();
831
+ }
832
+ if ((_a = window.rrweb) === null || _a === void 0 ? void 0 : _a.record) {
833
+ return Promise.resolve();
834
+ }
835
+ if (this.rrwebLoader) {
836
+ return this.rrwebLoader;
837
+ }
838
+ if (window.__SWETRIX_RRWEB_LOADING__) {
839
+ this.rrwebLoader = window.__SWETRIX_RRWEB_LOADING__;
840
+ void this.rrwebLoader.catch(() => {
841
+ if (window.__SWETRIX_RRWEB_LOADING__ === this.rrwebLoader) {
842
+ delete window.__SWETRIX_RRWEB_LOADING__;
843
+ }
844
+ this.rrwebLoader = null;
845
+ });
846
+ return this.rrwebLoader;
847
+ }
848
+ this.rrwebLoader = this.loadSessionReplayRecorder();
849
+ window.__SWETRIX_RRWEB_LOADING__ = this.rrwebLoader;
850
+ const loader = this.rrwebLoader;
851
+ void loader.catch(() => {
852
+ if (window.__SWETRIX_RRWEB_LOADING__ === loader) {
853
+ delete window.__SWETRIX_RRWEB_LOADING__;
854
+ }
855
+ if (this.rrwebLoader === loader) {
856
+ this.rrwebLoader = null;
857
+ }
858
+ });
859
+ return this.rrwebLoader;
860
+ }
861
+ async loadSessionReplayRecorder() {
862
+ const replayOption = this.getSessionReplayPreloadOption();
863
+ const hasCustomReplayUrl = replayOption && typeof replayOption === 'object' && replayOption.rrwebUrl;
864
+ if (hasCustomReplayUrl || this.getTrackerScript()) {
865
+ await this.loadSessionReplayScript(this.getSessionReplayUrl());
866
+ return;
867
+ }
868
+ if (await this.loadSessionReplayPackage()) {
869
+ return;
870
+ }
871
+ await this.loadSessionReplayScript(this.getDefaultSessionReplayUrl());
872
+ }
873
+ async loadSessionReplayPackage() {
874
+ try {
875
+ const rrwebModule = (await import('rrweb'));
876
+ const rrweb = rrwebModule.record ? rrwebModule : rrwebModule.default;
877
+ if (!(rrweb === null || rrweb === void 0 ? void 0 : rrweb.record)) {
878
+ return false;
879
+ }
880
+ window.rrweb = rrweb;
881
+ return true;
882
+ }
883
+ catch (_a) {
884
+ return false;
885
+ }
886
+ }
887
+ loadSessionReplayScript(url) {
888
+ return new Promise((resolve, reject) => {
889
+ const script = document.createElement('script');
890
+ script.async = true;
891
+ script.src = url;
892
+ script.crossOrigin = 'anonymous';
893
+ script.onload = () => resolve();
894
+ script.onerror = () => reject(new Error('Failed to load rrweb'));
895
+ document.head.appendChild(script);
896
+ });
897
+ }
898
+ getSessionReplayRecordOptions(privacy, userOptions, emit) {
899
+ const options = {
900
+ ...userOptions,
901
+ emit,
902
+ };
903
+ const maskInputOptions = typeof options.maskInputOptions === 'object' &&
904
+ options.maskInputOptions !== null
905
+ ? options.maskInputOptions
906
+ : {};
907
+ const resolvedPrivacy = this.getSessionReplayPrivacy(privacy);
908
+ if (resolvedPrivacy === 'total') {
909
+ return {
910
+ ...options,
911
+ maskAllInputs: true,
912
+ maskTextSelector: '*',
913
+ blockSelector: this.mergeSelectors(options.blockSelector, 'img, picture, video, audio, canvas, svg'),
914
+ recordCanvas: false,
915
+ inlineImages: false,
916
+ emit,
917
+ };
918
+ }
919
+ if (resolvedPrivacy === 'normal') {
920
+ return {
921
+ ...options,
922
+ maskAllInputs: true,
923
+ emit,
924
+ };
925
+ }
926
+ return {
927
+ ...options,
928
+ maskInputOptions: {
929
+ ...maskInputOptions,
930
+ password: true,
931
+ },
932
+ emit,
933
+ };
934
+ }
935
+ mergeSelectors(existing, required) {
936
+ if (typeof existing === 'string' && existing.trim()) {
937
+ return `${existing}, ${required}`;
938
+ }
939
+ return required;
940
+ }
941
+ createReplayId() {
942
+ if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
943
+ return crypto.randomUUID();
944
+ }
945
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
946
+ }
947
+ async sendSessionReplayStart(replayId, privacy) {
948
+ var _a, _b, _c;
949
+ try {
950
+ const apiBase = this.getApiBase();
951
+ const response = await fetch(`${apiBase}/log/session-replay/start`, {
952
+ method: 'POST',
953
+ headers: {
954
+ 'Content-Type': 'application/json',
955
+ },
956
+ body: JSON.stringify({
957
+ pid: this.projectID,
958
+ replayId,
959
+ privacy,
960
+ pg: this.activePage ||
961
+ getPath({
962
+ hash: (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.hash,
963
+ search: (_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.search,
964
+ }),
965
+ lc: getLocale(),
966
+ tz: getTimezone(),
967
+ profileId: (_c = this.options) === null || _c === void 0 ? void 0 : _c.profileId,
968
+ }),
969
+ });
970
+ return response.ok;
971
+ }
972
+ catch (_d) {
973
+ return false;
974
+ }
975
+ }
976
+ async sendSessionReplayChunk(replayId, privacy, chunkIndex, events, useBeacon) {
977
+ const apiBase = this.getApiBase();
978
+ const url = `${apiBase}/log/session-replay/chunk`;
979
+ const payload = JSON.stringify({
980
+ pid: this.projectID,
981
+ replayId,
982
+ privacy,
983
+ chunkIndex,
984
+ events,
985
+ });
986
+ if (useBeacon && typeof navigator.sendBeacon === 'function') {
987
+ const sent = navigator.sendBeacon(url, new Blob([payload], { type: 'application/json' }));
988
+ if (sent)
989
+ return;
990
+ }
991
+ try {
992
+ await fetch(url, {
993
+ method: 'POST',
994
+ headers: {
995
+ 'Content-Type': 'application/json',
996
+ },
997
+ keepalive: useBeacon,
998
+ body: payload,
999
+ });
1000
+ }
1001
+ catch (_a) { }
1002
+ }
596
1003
  async sendRequest(path, body) {
597
1004
  var _a;
598
1005
  const host = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.apiURL) || DEFAULT_API_HOST;
@@ -668,6 +1075,12 @@ function trackErrors(options) {
668
1075
  }
669
1076
  return LIB_INSTANCE.trackErrors(options);
670
1077
  }
1078
+ function startSessionReplay(options) {
1079
+ if (!LIB_INSTANCE) {
1080
+ return Promise.resolve(defaultSessionReplayActions);
1081
+ }
1082
+ return LIB_INSTANCE.startSessionReplay(options);
1083
+ }
671
1084
  /**
672
1085
  * This function is used to manually track an error event.
673
1086
  * It's useful if you want to track specific errors in your application.
@@ -702,17 +1115,16 @@ function pageview(options) {
702
1115
  }
703
1116
  /**
704
1117
  * Fetches all feature flags for the project.
705
- * Results are cached for 5 minutes by default.
1118
+ * Results are cached for 5 minutes by default and share a cache with experiments.
706
1119
  *
707
- * @param options - Options for evaluating feature flags (visitorId, attributes).
1120
+ * @param options - Options for evaluating feature flags (`profileId` only).
708
1121
  * @param forceRefresh - If true, bypasses the cache and fetches fresh flags.
709
1122
  * @returns A promise that resolves to a record of flag keys to boolean values.
710
1123
  *
711
1124
  * @example
712
1125
  * ```typescript
713
1126
  * const flags = await getFeatureFlags({
714
- * visitorId: 'user-123',
715
- * attributes: { cc: 'US', dv: 'desktop' }
1127
+ * profileId: 'user-123'
716
1128
  * })
717
1129
  *
718
1130
  * if (flags['new-checkout']) {
@@ -729,13 +1141,13 @@ async function getFeatureFlags(options, forceRefresh) {
729
1141
  * Gets the value of a single feature flag.
730
1142
  *
731
1143
  * @param key - The feature flag key.
732
- * @param options - Options for evaluating the feature flag (visitorId, attributes).
733
- * @param defaultValue - Default value to return if the flag is not found. Defaults to false.
1144
+ * @param options - Options for evaluating the feature flag (`profileId` only).
1145
+ * @param defaultValue - Optional default value to return if the flag is not found. Defaults to false.
734
1146
  * @returns A promise that resolves to the boolean value of the flag.
735
1147
  *
736
1148
  * @example
737
1149
  * ```typescript
738
- * const isEnabled = await getFeatureFlag('dark-mode', { visitorId: 'user-123' })
1150
+ * const isEnabled = await getFeatureFlag('dark-mode', { profileId: 'user-123' })
739
1151
  *
740
1152
  * if (isEnabled) {
741
1153
  * // Enable dark mode
@@ -748,8 +1160,8 @@ async function getFeatureFlag(key, options, defaultValue = false) {
748
1160
  return LIB_INSTANCE.getFeatureFlag(key, options, defaultValue);
749
1161
  }
750
1162
  /**
751
- * Clears the cached feature flags, forcing a fresh fetch on the next call.
752
- * Useful when you know the user's context has changed significantly.
1163
+ * Clears the cached feature flags and experiments, forcing a fresh fetch on the next call.
1164
+ * Useful when you know the user's profile has changed.
753
1165
  */
754
1166
  function clearFeatureFlagsCache() {
755
1167
  if (!LIB_INSTANCE)
@@ -757,10 +1169,10 @@ function clearFeatureFlagsCache() {
757
1169
  LIB_INSTANCE.clearFeatureFlagsCache();
758
1170
  }
759
1171
  /**
760
- * Fetches all A/B test experiments for the project.
1172
+ * Fetches variant assignments for running A/B test experiments returned by feature flag evaluation.
761
1173
  * Results are cached for 5 minutes by default (shared cache with feature flags).
762
1174
  *
763
- * @param options - Options for evaluating experiments.
1175
+ * @param options - Options for evaluating experiments (`profileId` only).
764
1176
  * @param forceRefresh - If true, bypasses the cache and fetches fresh data.
765
1177
  * @returns A promise that resolves to a record of experiment IDs to variant keys.
766
1178
  *
@@ -787,13 +1199,16 @@ async function getExperiments(options, forceRefresh) {
787
1199
  * Gets the variant key for a specific A/B test experiment.
788
1200
  *
789
1201
  * @param experimentId - The experiment ID.
790
- * @param options - Options for evaluating the experiment.
791
- * @param defaultVariant - Default variant key to return if the experiment is not found. Defaults to null.
1202
+ * @param options - Options for evaluating the experiment (`profileId` only).
1203
+ * @param defaultVariant - Optional default variant key to return if the experiment is not found. Defaults to null.
792
1204
  * @returns A promise that resolves to the variant key assigned to this user, or defaultVariant if not found.
793
1205
  *
794
1206
  * @example
795
1207
  * ```typescript
796
- * const variant = await getExperiment('checkout-redesign-experiment-id')
1208
+ * const variant = await getExperiment('checkout-redesign-experiment-id', { profileId: 'user-123' })
1209
+ *
1210
+ * // Optional fallback variant:
1211
+ * const variantWithFallback = await getExperiment('checkout-redesign-experiment-id', undefined, 'control')
797
1212
  *
798
1213
  * if (variant === 'new-checkout') {
799
1214
  * // Show new checkout flow
@@ -877,5 +1292,5 @@ async function getSessionId() {
877
1292
  return LIB_INSTANCE.getSessionId();
878
1293
  }
879
1294
 
880
- export { LIB_INSTANCE, clearExperimentsCache, clearFeatureFlagsCache, getExperiment, getExperiments, getFeatureFlag, getFeatureFlags, getProfileId, getSessionId, init, pageview, track, trackError, trackErrors, trackPageview, trackViews };
1295
+ export { LIB_INSTANCE, clearExperimentsCache, clearFeatureFlagsCache, getExperiment, getExperiments, getFeatureFlag, getFeatureFlags, getProfileId, getSessionId, init, pageview, startSessionReplay, track, trackError, trackErrors, trackPageview, trackViews };
881
1296
  //# sourceMappingURL=swetrix.es5.js.map