tessl install tessl/npm-posthog-js@1.335.0PostHog Browser JS Library is a comprehensive browser analytics and feature management SDK that enables developers to capture user events, track product analytics, manage feature flags, record session replays, and implement feedback mechanisms like surveys and conversations in web applications.
Session recording captures user interactions, page views, and behaviors to help you understand how users experience your application.
Starts session recording, optionally overriding trigger requirements.
/**
* Starts session recording
* @param override - Override specific trigger requirements, or true to override all
*/
function startSessionRecording(override?: {
sampling?: boolean;
linked_flag?: boolean;
url_trigger?: boolean;
event_trigger?: boolean;
} | true): void;Usage Examples:
// Start recording unconditionally
posthog.startSessionRecording();
// Start with all overrides
posthog.startSessionRecording(true);
// Override specific triggers
posthog.startSessionRecording({
sampling: true, // Override sample rate
linked_flag: true, // Override feature flag requirement
url_trigger: false, // Still require URL match
event_trigger: false // Still require event trigger
});
// Start after user action
function onUserConsent() {
posthog.startSessionRecording();
}
// Conditional recording
if (user.plan === 'premium') {
posthog.startSessionRecording();
}Stops the current session recording.
/**
* Stops the current session recording
*/
function stopSessionRecording(): void;Usage Examples:
// Stop recording
posthog.stopSessionRecording();
// Stop on sensitive page
router.on('route', (route) => {
if (route.path.includes('/payment')) {
posthog.stopSessionRecording();
}
});
// Stop on user request
function disableRecording() {
posthog.stopSessionRecording();
localStorage.setItem('recording_disabled', 'true');
}Checks if session recording is currently active.
/**
* Checks if session recording is currently active
* @returns True if recording is active, false otherwise
*/
function sessionRecordingStarted(): boolean;Usage Examples:
// Check status
if (posthog.sessionRecordingStarted()) {
console.log('Session is being recorded');
}
// Conditional UI
function RecordingIndicator() {
const isRecording = posthog.sessionRecordingStarted();
return isRecording ? <div>Recording</div> : null;
}
// Start if not already started
if (!posthog.sessionRecordingStarted()) {
posthog.startSessionRecording();
}Gets the current session ID.
/**
* Gets the current session ID
* @returns The current session ID
*/
function get_session_id(): string;Usage Examples:
// Get session ID
const sessionId = posthog.get_session_id();
console.log('Current session:', sessionId);
// Include in API calls
fetch('/api/data', {
headers: {
'X-Session-ID': posthog.get_session_id()
}
});
// Track session across services
const sessionData = {
sessionId: posthog.get_session_id(),
userId: posthog.get_distinct_id()
};Gets the URL to view the session replay in PostHog.
/**
* Gets the URL to the session replay
* @param options - Options for replay URL generation
* @returns URL to view the session replay
*/
function get_session_replay_url(options?: {
withTimestamp?: boolean;
timestampLookBack?: number;
}): string;Usage Examples:
// Get basic replay URL
const replayUrl = posthog.get_session_replay_url();
console.log('View replay:', replayUrl);
// Get URL with current timestamp
const urlWithTime = posthog.get_session_replay_url({
withTimestamp: true
});
// Get URL with lookback (seconds before current time)
const urlWithLookback = posthog.get_session_replay_url({
withTimestamp: true,
timestampLookBack: 30 // 30 seconds before now
});
// Share replay with support
function shareReplayWithSupport(issueDescription) {
const replayUrl = posthog.get_session_replay_url({
withTimestamp: true
});
sendToSupport({
description: issueDescription,
replayUrl: replayUrl,
sessionId: posthog.get_session_id()
});
}Registers a callback that fires when the session ID changes.
/**
* Registers a callback for when the session ID changes
* @param callback - Function to call when session changes
* @returns Function to unsubscribe from callback
*/
function onSessionId(callback: SessionIdChangedCallback): () => void;Usage Examples:
// Listen for session changes
const unsubscribe = posthog.onSessionId((sessionId, windowId) => {
console.log('New session:', sessionId);
console.log('Window ID:', windowId);
// Track session change
trackSessionChange(sessionId);
});
// Stop listening
unsubscribe();
// React to session changes
posthog.onSessionId((sessionId) => {
// Update UI with new session
updateSessionDisplay(sessionId);
// Sync with backend
syncSessionToBackend(sessionId);
});The posthog.sessionRecording property provides access to advanced session recording controls. These methods allow programmatic control over recording behavior and are primarily used for debugging or advanced use cases.
Checks if session recording is currently active.
/**
* Checks if session recording is currently active
* @returns True if recording is active, false otherwise
*/
readonly started: boolean; // Accessed as posthog.sessionRecording.startedUsage Examples:
// Check if recording is active
if (posthog.sessionRecording && posthog.sessionRecording.started) {
console.log('Session recording is active');
} else {
console.log('Session recording is not active');
}
// Show recording indicator
function RecordingStatusIndicator() {
const isRecording = posthog.sessionRecording?.started ?? false;
return isRecording ? <span>🔴 Recording</span> : null;
}
// Conditional logic based on recording state
function handleSensitiveAction() {
if (posthog.sessionRecording?.started) {
// Pause recording for sensitive operations
posthog.stopSessionRecording();
performSensitiveAction();
posthog.startSessionRecording();
} else {
performSensitiveAction();
}
}Programmatically overrides the linked feature flag requirement for session recording.
/**
* Overrides the linked feature flag requirement
* Allows recording to start regardless of feature flag state
*/
posthog.sessionRecording.overrideLinkedFlag(): void;Usage Examples:
// Force recording regardless of feature flag
if (posthog.sessionRecording) {
posthog.sessionRecording.overrideLinkedFlag();
posthog.startSessionRecording();
}
// Record VIP user sessions regardless of flag
if (user.isVIP) {
posthog.sessionRecording?.overrideLinkedFlag();
posthog.startSessionRecording();
}Programmatically overrides the sampling decision for session recording.
/**
* Overrides the sampling decision
* Allows recording to start regardless of configured sample rate
*/
posthog.sessionRecording.overrideSampling(): void;Usage Examples:
// Force recording regardless of sample rate
if (posthog.sessionRecording) {
posthog.sessionRecording.overrideSampling();
posthog.startSessionRecording();
}
// Record sessions for support tickets
function openSupportTicket() {
posthog.sessionRecording?.overrideSampling();
posthog.startSessionRecording();
const replayUrl = posthog.get_session_replay_url();
createTicket({ replayUrl });
}Programmatically overrides specific trigger requirements for session recording.
/**
* Overrides specific trigger requirement
* @param triggerType - Type of trigger to override ('url' or 'event')
*/
posthog.sessionRecording.overrideTrigger(triggerType: 'url' | 'event'): void;Usage Examples:
// Override URL trigger requirement
if (posthog.sessionRecording) {
posthog.sessionRecording.overrideTrigger('url');
posthog.startSessionRecording();
}
// Override event trigger requirement
if (posthog.sessionRecording) {
posthog.sessionRecording.overrideTrigger('event');
posthog.startSessionRecording();
}
// Start recording on button click, ignoring triggers
function handleDebugRecording() {
if (posthog.sessionRecording) {
posthog.sessionRecording.overrideTrigger('url');
posthog.sessionRecording.overrideTrigger('event');
posthog.startSessionRecording();
}
}Debug property to enable network capture on localhost. This is intended for development and debugging purposes only.
/**
* Forces network capture on localhost for debugging
* WARNING: Development/debugging use only
*/
posthog.sessionRecording._forceAllowLocalhostNetworkCapture: boolean;Usage Examples:
// Enable network capture in local development
if (process.env.NODE_ENV === 'development' && posthog.sessionRecording) {
posthog.sessionRecording._forceAllowLocalhostNetworkCapture = true;
posthog.startSessionRecording();
}
// Debug network requests locally
if (window.location.hostname === 'localhost' && posthog.sessionRecording) {
posthog.sessionRecording._forceAllowLocalhostNetworkCapture = true;
}Note: This property is prefixed with _ to indicate it's for debugging purposes and should not be used in production code.
/**
* Callback invoked when session ID changes
*/
type SessionIdChangedCallback = (sessionId: string, windowId: string) => void;/**
* Configuration for session recording
*/
interface SessionRecordingOptions {
/**
* Enable or disable session recording
* @default undefined (uses server-side config)
*/
enabled?: boolean;
/**
* Mask all input fields
* @default false
*/
maskAllInputs?: boolean;
/**
* CSS selector for text elements to mask
*/
maskTextSelector?: string;
/**
* CSS selector for elements to completely block from recording
*/
blockSelector?: string;
/**
* Record cross-origin iframes
* @default false
*/
recordCrossOriginIframes?: boolean;
/**
* Sample rate for session recording (0-1)
* 0.1 = 10% of sessions recorded
*/
sampleRate?: number;
/**
* Minimum session duration to record (milliseconds)
*/
minimumDurationMilliseconds?: number;
/**
* Feature flag controlling recording
*/
linkedFlag?: string | FlagVariant;
/**
* Enable canvas recording
* @default false
*/
recordCanvas?: boolean;
/**
* Capture console logs in recordings
* @default true
*/
consoleLogRecordingEnabled?: boolean;
/**
* Capture network activity
*/
networkPayloadCapture?: {
/**
* Record request/response headers
*/
recordHeaders?: boolean | {
request: boolean;
response: boolean;
};
/**
* Record request/response bodies
*/
recordBody?: boolean | string[] | {
request: boolean | string[];
response: boolean | string[];
};
};
/**
* Capture performance data
* @default true
*/
capturePerformance?: boolean;
/**
* URL triggers for recording
*/
urlTriggers?: string[];
/**
* Event triggers for recording
*/
eventTriggers?: string[];
/**
* Mask text content
* @default false
*/
maskTextContent?: boolean;
/**
* Mask captured network requests
*/
maskCapturedNetworkRequestFn?: (data: NetworkRequest) => NetworkRequest | null;
}/**
* Feature flag variant configuration
*/
interface FlagVariant {
/**
* Feature flag key
*/
flag: string;
/**
* Required variant value
*/
variant: string;
}/**
* Network request data captured during recording
*/
interface NetworkRequest {
/**
* Request URL
*/
url: string;
/**
* HTTP method
*/
method: string;
/**
* Request headers
*/
headers?: Record<string, string>;
/**
* Request body
*/
body?: string;
/**
* Response status
*/
status?: number;
/**
* Response headers
*/
responseHeaders?: Record<string, string>;
/**
* Response body
*/
responseBody?: string;
}Configure session recording during initialization:
// Basic configuration
posthog.init('token', {
session_recording: {
enabled: true,
maskAllInputs: true,
consoleLogRecordingEnabled: true
}
});
// Privacy-focused configuration
posthog.init('token', {
session_recording: {
enabled: true,
maskAllInputs: true,
maskTextContent: true,
blockSelector: '.sensitive-data',
networkPayloadCapture: {
recordHeaders: false,
recordBody: false
}
}
});
// Advanced configuration
posthog.init('token', {
session_recording: {
enabled: true,
sampleRate: 0.1, // Record 10% of sessions
minimumDurationMilliseconds: 5000, // Only record sessions > 5s
linkedFlag: 'record-sessions', // Require feature flag
recordCanvas: true,
recordCrossOriginIframes: true,
networkPayloadCapture: {
recordHeaders: {
request: true,
response: false
},
recordBody: {
request: ['application/json'],
response: ['application/json']
}
}
}
});
// Disable session recording
posthog.init('token', {
disable_session_recording: true
});Configure what data to mask in recordings:
posthog.init('token', {
session_recording: {
// Mask all inputs (passwords, credit cards, etc.)
maskAllInputs: true,
// Mask specific text elements
maskTextSelector: '.user-name, .email, .phone',
// Block elements completely (won't appear in recording)
blockSelector: '.sensitive-section, .payment-info',
// Custom network masking
maskCapturedNetworkRequestFn: (data) => {
// Remove sensitive headers
if (data.headers) {
delete data.headers['Authorization'];
delete data.headers['Cookie'];
}
// Mask sensitive URLs
if (data.url.includes('/api/secret')) {
return null; // Don't capture this request
}
return data;
}
}
});Always consider privacy when recording sessions:
// ✅ Good: Get user consent
function requestRecordingConsent() {
const consent = confirm('May we record your session to improve our service?');
if (consent) {
posthog.startSessionRecording();
localStorage.setItem('recording_consent', 'granted');
}
}
// ✅ Good: Stop recording on sensitive pages
router.on('route', (route) => {
const sensitivePaths = ['/payment', '/settings/security', '/admin'];
if (sensitivePaths.some(path => route.path.includes(path))) {
posthog.stopSessionRecording();
}
});
// ✅ Good: Mask sensitive data
posthog.init('token', {
session_recording: {
maskAllInputs: true,
blockSelector: '.payment-form, .ssn, .credit-card'
}
});Record sessions based on specific conditions:
// Record only for authenticated users
if (user.isAuthenticated) {
posthog.startSessionRecording();
}
// Record based on plan
if (user.plan === 'enterprise' || user.plan === 'pro') {
posthog.startSessionRecording();
}
// Record when feature flag is enabled
posthog.onFeatureFlags((flags) => {
if (flags['enable-session-recording']) {
posthog.startSessionRecording();
}
});
// Sample recording (10% of sessions)
if (Math.random() < 0.1) {
posthog.startSessionRecording();
}Include session replay URLs in error reports:
// Add replay to error tracking
window.addEventListener('error', (event) => {
const replayUrl = posthog.get_session_replay_url({
withTimestamp: true,
timestampLookBack: 10
});
logError({
message: event.message,
stack: event.error?.stack,
replayUrl: replayUrl,
sessionId: posthog.get_session_id()
});
});
// Include in support tickets
function submitSupportTicket(description) {
const ticket = {
description: description,
sessionReplay: posthog.get_session_replay_url({
withTimestamp: true
}),
sessionId: posthog.get_session_id(),
userId: posthog.get_distinct_id()
};
sendToSupport(ticket);
}Optimize recording for performance:
// Only record sessions longer than threshold
posthog.init('token', {
session_recording: {
minimumDurationMilliseconds: 10000 // 10 seconds
}
});
// Disable canvas recording if not needed
posthog.init('token', {
session_recording: {
recordCanvas: false // Better performance
}
});
// Limit network capture
posthog.init('token', {
session_recording: {
networkPayloadCapture: {
recordHeaders: false,
recordBody: ['application/json'] // Only JSON bodies
}
}
});Integrate session replays with customer support:
function CustomerSupportWidget() {
const [sessionUrl, setSessionUrl] = useState('');
useEffect(() => {
// Get replay URL when widget opens
const url = posthog.get_session_replay_url({
withTimestamp: true
});
setSessionUrl(url);
}, []);
function sendMessage(message) {
submitToSupport({
message: message,
sessionReplay: sessionUrl,
sessionId: posthog.get_session_id(),
userEmail: user.email
});
}
return (
<div>
<textarea onChange={e => setMessage(e.target.value)} />
<button onClick={() => sendMessage(message)}>
Send (includes session replay)
</button>
</div>
);
}Link errors to session replays:
// Sentry integration
Sentry.init({
beforeSend(event) {
// Add session replay URL to Sentry events
event.contexts = {
...event.contexts,
posthog: {
session_id: posthog.get_session_id(),
replay_url: posthog.get_session_replay_url({
withTimestamp: true
})
}
};
return event;
}
});
// Custom error handler
class ErrorHandler {
captureError(error) {
const errorReport = {
message: error.message,
stack: error.stack,
timestamp: Date.now(),
sessionReplay: posthog.get_session_replay_url({
withTimestamp: true,
timestampLookBack: 30
}),
sessionId: posthog.get_session_id()
};
this.sendToBackend(errorReport);
}
}Record specific pages or flows:
// Record only important user flows
const recordedRoutes = [
'/checkout',
'/onboarding',
'/settings',
'/dashboard'
];
router.on('route', (route) => {
const shouldRecord = recordedRoutes.some(r =>
route.path.startsWith(r)
);
if (shouldRecord && !posthog.sessionRecordingStarted()) {
posthog.startSessionRecording();
} else if (!shouldRecord && posthog.sessionRecordingStarted()) {
posthog.stopSessionRecording();
}
});Use recordings for user research and testing:
// Tag test sessions
posthog.capture('user_test_started', {
test_id: 'checkout-flow-test-v2',
participant_id: 'P001'
});
posthog.startSessionRecording();
// Track test milestones
function trackTestStep(stepName) {
posthog.capture('user_test_step', {
step: stepName,
session_id: posthog.get_session_id()
});
}
// End test with replay link
function endUserTest() {
const replayUrl = posthog.get_session_replay_url();
posthog.capture('user_test_completed', {
replay_url: replayUrl
});
posthog.stopSessionRecording();
}Record sessions for experiment analysis:
// Record variant exposure
posthog.onFeatureFlags((flags) => {
const variant = flags['checkout-experiment'];
if (variant) {
// Tag session with variant
posthog.register({
experiment_variant: variant
});
// Start recording for experiment analysis
posthog.startSessionRecording();
posthog.capture('experiment_exposure', {
experiment: 'checkout-experiment',
variant: variant,
session_id: posthog.get_session_id()
});
}
});Detect and record frustrated user interactions:
let clickCount = 0;
let clickTimer = null;
const RAGE_CLICK_THRESHOLD = 5;
const RAGE_CLICK_WINDOW = 2000; // 2 seconds
document.addEventListener('click', (event) => {
clickCount++;
if (clickTimer) {
clearTimeout(clickTimer);
}
if (clickCount >= RAGE_CLICK_THRESHOLD) {
// Rage click detected
console.log('Rage click detected!');
// Ensure recording is active
if (!posthog.sessionRecordingStarted()) {
posthog.startSessionRecording();
}
// Capture event with replay
posthog.capture('rage_click_detected', {
element: event.target.tagName,
click_count: clickCount,
replay_url: posthog.get_session_replay_url({
withTimestamp: true,
timestampLookBack: 10
})
});
clickCount = 0;
}
clickTimer = setTimeout(() => {
clickCount = 0;
}, RAGE_CLICK_WINDOW);
});// Record based on multiple conditions
function shouldRecordSession(user: User, page: string): boolean {
// Don't record for internal users
if (user.email?.endsWith('@company.com')) {
return false;
}
// Record premium users
if (user.plan === 'premium' || user.plan === 'enterprise') {
return true;
}
// Record important flows for all users
const importantFlows = ['/checkout', '/onboarding', '/payment'];
if (importantFlows.some(flow => page.startsWith(flow))) {
return true;
}
// Sample other sessions (10%)
return Math.random() < 0.1;
}
// Apply conditional recording
if (shouldRecordSession(currentUser, window.location.pathname)) {
posthog.startSessionRecording();
}// Use feature flags to control recording
posthog.onFeatureFlags((flags) => {
const recordingConfig = posthog.getFeatureFlagPayload('recording-config') as {
enabled: boolean;
sampleRate: number;
maskInputs: boolean;
} | undefined;
if (recordingConfig?.enabled) {
if (Math.random() < recordingConfig.sampleRate) {
posthog.set_config({
session_recording: {
enabled: true,
maskAllInputs: recordingConfig.maskInputs
}
});
posthog.startSessionRecording();
}
}
});// Advanced network request filtering
posthog.init('token', {
session_recording: {
enabled: true,
networkPayloadCapture: {
recordHeaders: {
request: true,
response: false
},
recordBody: {
request: ['application/json'],
response: ['application/json']
}
},
maskCapturedNetworkRequestFn: (request) => {
// Don't capture authentication requests
if (request.url.includes('/auth/') || request.url.includes('/login')) {
return null;
}
// Mask sensitive headers
if (request.headers) {
const maskedHeaders = { ...request.headers };
delete maskedHeaders['Authorization'];
delete maskedHeaders['Cookie'];
delete maskedHeaders['X-API-Key'];
request.headers = maskedHeaders;
}
// Mask sensitive response fields
if (request.responseBody) {
try {
const body = JSON.parse(request.responseBody);
if (body.token) body.token = '[MASKED]';
if (body.password) body.password = '[MASKED]';
if (body.credit_card) body.credit_card = '[MASKED]';
request.responseBody = JSON.stringify(body);
} catch (e) {
// Not JSON, skip masking
}
}
return request;
}
}
});// Handle recording failure gracefully
function startRecordingSafely() {
try {
if (posthog.sessionRecording) {
posthog.startSessionRecording();
// Verify it started
setTimeout(() => {
if (!posthog.sessionRecordingStarted()) {
console.warn('Session recording failed to start');
// Log to monitoring service
logWarning('session_recording_failed');
}
}, 1000);
}
} catch (error) {
console.error('Error starting session recording:', error);
}
}// Handle session ID changes
let currentSessionId = posthog.get_session_id();
posthog.onSessionId((newSessionId, windowId) => {
console.log('Session changed:', {
old: currentSessionId,
new: newSessionId,
windowId: windowId
});
// Track session transition
posthog.capture('session_transitioned', {
previous_session: currentSessionId,
new_session: newSessionId,
window_id: windowId
});
currentSessionId = newSessionId;
// Restart recording for new session if needed
if (shouldRecordCurrentPage()) {
posthog.startSessionRecording();
}
});// Prevent memory leaks with long-running recordings
class RecordingManager {
private maxRecordingTime = 30 * 60 * 1000; // 30 minutes
private recordingTimer?: NodeJS.Timeout;
startRecording() {
posthog.startSessionRecording();
// Stop after max time
this.recordingTimer = setTimeout(() => {
console.log('Max recording time reached, restarting');
this.restartRecording();
}, this.maxRecordingTime);
}
stopRecording() {
if (this.recordingTimer) {
clearTimeout(this.recordingTimer);
}
posthog.stopSessionRecording();
}
restartRecording() {
this.stopRecording();
// Wait briefly before restarting
setTimeout(() => {
this.startRecording();
}, 1000);
}
}// Disable expensive features if not needed
posthog.init('token', {
session_recording: {
enabled: true,
// Disable canvas recording (expensive)
recordCanvas: false,
// Disable console log recording if not needed
consoleLogRecordingEnabled: false,
// Minimal network capture
networkPayloadCapture: {
recordHeaders: false,
recordBody: false
},
// Don't capture performance (if not needed)
capturePerformance: false
}
});// Adjust recording based on device performance
function getRecordingConfig(): SessionRecordingOptions {
const isLowEndDevice = (
navigator.deviceMemory && navigator.deviceMemory < 4 ||
navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4
);
if (isLowEndDevice) {
return {
enabled: true,
recordCanvas: false,
consoleLogRecordingEnabled: false,
networkPayloadCapture: undefined,
capturePerformance: false
};
}
return {
enabled: true,
recordCanvas: true,
consoleLogRecordingEnabled: true,
capturePerformance: true
};
}
posthog.init('token', {
session_recording: getRecordingConfig()
});// Debug recording issues
function debugRecording() {
console.log('Recording started:', posthog.sessionRecordingStarted());
console.log('Recording disabled:', posthog.config.disable_session_recording);
console.log('Recording config:', posthog.config.session_recording);
console.log('Session ID:', posthog.get_session_id());
// Check if sessionRecording API is available
console.log('Recording API available:', !!posthog.sessionRecording);
if (posthog.sessionRecording) {
console.log('Recording started:', posthog.sessionRecording.started);
}
// Try force starting
console.log('Force starting...');
posthog.startSessionRecording(true);
setTimeout(() => {
console.log('Recording started after force:', posthog.sessionRecordingStarted());
}, 1000);
}// Verify replay URL generation
function getReplayUrlSafely(): string | null {
if (!posthog.sessionRecordingStarted()) {
console.warn('Recording not started, cannot get replay URL');
return null;
}
try {
const url = posthog.get_session_replay_url({
withTimestamp: true
});
if (!url || url.includes('undefined')) {
console.warn('Invalid replay URL generated:', url);
return null;
}
return url;
} catch (error) {
console.error('Error generating replay URL:', error);
return null;
}
}// Monitor recording performance impact
class RecordingPerformanceMonitor {
private metrics = {
memoryBefore: 0,
memoryAfter: 0,
startTime: 0
};
start() {
this.metrics.memoryBefore = (performance as any).memory?.usedJSHeapSize || 0;
this.metrics.startTime = Date.now();
posthog.startSessionRecording();
// Check impact after 10 seconds
setTimeout(() => this.check(), 10000);
}
check() {
this.metrics.memoryAfter = (performance as any).memory?.usedJSHeapSize || 0;
const memoryIncrease = this.metrics.memoryAfter - this.metrics.memoryBefore;
const duration = Date.now() - this.metrics.startTime;
console.log('Recording performance:', {
duration_ms: duration,
memory_increase_mb: memoryIncrease / 1024 / 1024,
memory_rate_mb_per_min: (memoryIncrease / 1024 / 1024) / (duration / 60000)
});
// Stop if memory usage is too high
if (memoryIncrease > 50 * 1024 * 1024) { // 50 MB
console.warn('Recording using too much memory, stopping');
posthog.stopSessionRecording();
}
}
}