or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/posthog-js@1.335.x

docs

index.md
tile.json

tessl/npm-posthog-js

tessl install tessl/npm-posthog-js@1.335.0

PostHog 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.mddocs/reference/

Session Recording

Session recording captures user interactions, page views, and behaviors to help you understand how users experience your application.

Capabilities

Start Session Recording

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();
}

Stop Session Recording

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');
}

Check Recording Status

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();
}

Get Session ID

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()
};

Get Session Replay URL

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()
    });
}

Session ID Change Callback

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);
});

SessionRecording Sub-API

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.

Check Recording Status

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.started

Usage 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();
    }
}

Override Linked Flag

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();
}

Override Sampling

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 });
}

Override Trigger

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();
    }
}

Force Localhost Network Capture (Debug Only)

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.

Types

SessionIdChangedCallback

/**
 * Callback invoked when session ID changes
 */
type SessionIdChangedCallback = (sessionId: string, windowId: string) => void;

SessionRecordingOptions

/**
 * 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;
}

FlagVariant

/**
 * Feature flag variant configuration
 */
interface FlagVariant {
    /**
     * Feature flag key
     */
    flag: string;

    /**
     * Required variant value
     */
    variant: string;
}

NetworkRequest

/**
 * 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;
}

Configuration

Session Recording Settings

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
});

Privacy Masking

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;
        }
    }
});

Best Practices

Respect User Privacy

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'
    }
});

Conditional Recording

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();
}

Error Context

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);
}

Performance Considerations

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
        }
    }
});

Common Patterns

Support Integration

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>
    );
}

Error Tracking Integration

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);
    }
}

Conditional Recording by Route

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();
    }
});

Session Replay in User Research

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();
}

A/B Test Recordings

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()
        });
    }
});

Rage Click Detection

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);
});

Advanced Recording Patterns

Conditional Recording Based on User State

// 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();
}

Recording with Feature Flags

// 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();
        }
    }
});

Network Payload Filtering

// 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;
        }
    }
});

Edge Cases & Error Handling

Recording Initialization Failure

// 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 Transitions

// 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();
    }
});

Memory Management

// 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);
    }
}

Performance Optimization

Minimize Recording Overhead

// 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
    }
});

Adaptive Recording Quality

// 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()
});

Troubleshooting

Recording Not Starting

// 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);
}

Replay URL Not Generated

// 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;
    }
}

Recording Performance Impact

// 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();
        }
    }
}

See Also

  • Initialization - Configure session recording
  • Privacy - Privacy and consent for recordings
  • Error Tracking - Link errors to session replays
  • Feature Flags - Control recording with flags
  • Types - Session recording type definitions