Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export class SessionReplayPlugin implements EnrichmentPlugin<BrowserClient, Brow
shouldInlineStylesheet: this.options.shouldInlineStylesheet,
version: { type: 'plugin', version: VERSION },
performanceConfig: this.options.performanceConfig,
delayRecordInitialization: this.options.delayRecordInitialization,
storeType: this.options.storeType,
experimental: this.options.experimental,
userProperties: userProperties,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export interface SessionReplayPerformanceConfig {
timeout?: number;
}

export interface SessionReplayDelayRecordInitializationConfig {
enabled: boolean;
timeout?: number;
}

/**
* UGC filter rule.
*/
Expand Down Expand Up @@ -79,6 +84,10 @@ export interface SessionReplayOptions {
* @see {@link StandaloneSessionReplayOptions.performanceConfig}
*/
performanceConfig?: SessionReplayPerformanceConfig;
/**
* @see {@link StandaloneSessionReplayOptions.delayRecordInitialization}
*/
delayRecordInitialization?: SessionReplayDelayRecordInitializationConfig;
/**
* @see {@link StandaloneSessionReplayOptions.storeType}
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/session-replay-browser/src/config/local-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
DEFAULT_SAMPLE_RATE,
DEFAULT_SERVER_ZONE,
DEFAULT_URL_CHANGE_POLLING_INTERVAL,
DEFAULT_DELAY_RECORD_INITIALIZATION_CONFIG,
} from '../constants';
import { SessionReplayOptions, StoreType } from '../typings/session-replay';
import {
Expand All @@ -12,6 +13,7 @@ import {
PrivacyConfig,
SessionReplayPerformanceConfig,
SessionReplayVersion,
SessionReplayDelayRecordInitializationConfig,
} from './types';
import { SafeLoggerProvider } from '../logger';
import { validateUGCFilterRules } from '../helpers';
Expand All @@ -35,6 +37,7 @@ export class SessionReplayLocalConfig extends Config implements ISessionReplayLo
version?: SessionReplayVersion;
storeType: StoreType;
performanceConfig?: SessionReplayPerformanceConfig;
delayRecordInitialization?: SessionReplayDelayRecordInitializationConfig;
experimental?: { useWebWorker: boolean };
applyBackgroundColorToBlockedElements?: boolean;
omitElementTags?: {
Expand Down Expand Up @@ -66,6 +69,7 @@ export class SessionReplayLocalConfig extends Config implements ISessionReplayLo
this.shouldInlineStylesheet = options.shouldInlineStylesheet;
this.version = options.version;
this.performanceConfig = options.performanceConfig || DEFAULT_PERFORMANCE_CONFIG;
this.delayRecordInitialization = options.delayRecordInitialization || DEFAULT_DELAY_RECORD_INITIALIZATION_CONFIG;
this.storeType = options.storeType ?? 'idb';
this.applyBackgroundColorToBlockedElements = options.applyBackgroundColorToBlockedElements ?? false;
this.enableUrlChangePolling = options.enableUrlChangePolling ?? false;
Expand Down
19 changes: 19 additions & 0 deletions packages/session-replay-browser/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ export interface SessionReplayLocalConfig extends IConfig {
* to be done during the browser's idle periods.
*/
performanceConfig?: SessionReplayPerformanceConfig;
/**
* Delay record initialization configuration. If enabled, we will defer record function initialization
* to be done during the browser's idle periods.
*/
delayRecordInitialization?: SessionReplayDelayRecordInitializationConfig;
/**
* Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events
* when all events cannot be sent during capture. `memory` stores replay events only in memory,
Expand Down Expand Up @@ -253,4 +258,18 @@ export interface SessionReplayPerformanceConfig {
timeout?: number;
}

export interface SessionReplayDelayRecordInitializationConfig {
/**
* If enabled, we will defer record function initialization
* to be done during the browser's idle periods.
*/
enabled: boolean;
/**
* Optional timeout in milliseconds for the `requestIdleCallback` API.
* If specified, this value will be used to set a maximum time for the browser to wait
* before executing the deferred record function initialization, even if the browser is not idle.
*/
timeout?: number;
}

export type SessionReplayType = 'standalone' | 'plugin' | 'segment';
1 change: 1 addition & 0 deletions packages/session-replay-browser/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const DEFAULT_SAMPLE_RATE = 0;
export const DEFAULT_SERVER_ZONE = ServerZone.US;
export const DEFAULT_PERFORMANCE_CONFIG = { enabled: true };
export const DEFAULT_URL_CHANGE_POLLING_INTERVAL = 1000;
export const DEFAULT_DELAY_RECORD_INITIALIZATION_CONFIG = { enabled: false };

export const SESSION_REPLAY_DEBUG_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay Debug`;

Expand Down
35 changes: 35 additions & 0 deletions packages/session-replay-browser/src/session-replay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ export class SessionReplay implements AmplitudeSessionReplay {
sessionTargetingMatch: this.sessionTargetingMatch,
event: eventForTargeting,
targetingParams: targetingParams,
config: this.config.targetingConfig,
},
null,
2,
Expand Down Expand Up @@ -531,6 +532,40 @@ export class SessionReplay implements AmplitudeSessionReplay {
}
this.stopRecordingEvents();

const shouldUseIdleCallback = config?.delayRecordInitialization?.enabled;
if (shouldUseIdleCallback) {
this.loggerProvider.debug('Scheduling record function initialization during idle time.');
this.scheduleIdleRecordInitialization(shouldLogMetadata, config, sessionId);
} else {
this.loggerProvider.debug('Initializing record function immediately.');
await this.initializeRecording(shouldLogMetadata, config, sessionId);
}
}

private scheduleIdleRecordInitialization(
shouldLogMetadata: boolean,
config: SessionReplayJoinedConfig,
sessionId: string | number,
) {
const timeout = config?.delayRecordInitialization?.timeout || 2000;

const globalScope = getGlobalScope();
if (globalScope?.requestIdleCallback) {
globalScope.requestIdleCallback(
() => {
this.loggerProvider.debug('Initializing record function during idle time.');
void this.initializeRecording(shouldLogMetadata, config, sessionId);
},
{ timeout },
);
}
}

private async initializeRecording(
shouldLogMetadata: boolean,
config: SessionReplayJoinedConfig,
sessionId: string | number,
) {
const recordFunction = await this.getRecordFunction();

// May be undefined if cannot import rrweb-record
Expand Down
Loading