diff --git a/src/__tests__/extensions/replay/sessionrecording.test.ts b/src/__tests__/extensions/replay/sessionrecording.test.ts index 255ee304d..e384f7776 100644 --- a/src/__tests__/extensions/replay/sessionrecording.test.ts +++ b/src/__tests__/extensions/replay/sessionrecording.test.ts @@ -344,10 +344,39 @@ describe('SessionRecording', () => { '%s', (_name: string, serverSide: boolean | undefined, clientSide: boolean | undefined, expected: boolean) => { posthog.persistence?.register({ - [SESSION_RECORDING_CANVAS_RECORDING]: { enabled: serverSide, fps: 4, quality: 0.1 }, + [SESSION_RECORDING_CANVAS_RECORDING]: { enabled: serverSide, fps: 4, quality: '0.1' }, }) posthog.config.session_recording.captureCanvas = { recordCanvas: clientSide } - expect(sessionRecording['canvasRecording']).toMatchObject({ enabled: expected }) + expect(sessionRecording['canvasRecording']).toMatchObject({ enabled: expected, fps: 4, quality: 0.1 }) + } + ) + + it.each([ + ['max fps and quality', 12, '1.0', 12, 1], + ['min fps and quality', 0, '0.0', 0, 0], + ['mid fps and quality', 6, '0.5', 6, 0.5], + ['null fps and quality', null, null, 4, 0.4], + ['undefined fps and quality', undefined, undefined, 4, 0.4], + ['string fps and quality', '12', '1.0', 4, 1], + ['over max fps and quality', 15, '1.5', 12, 1], + ])( + '%s', + ( + _name: string, + fps: number | string | null | undefined, + quality: string | null | undefined, + expectedFps: number, + expectedQuality: number + ) => { + posthog.persistence?.register({ + [SESSION_RECORDING_CANVAS_RECORDING]: { enabled: true, fps, quality }, + }) + + expect(sessionRecording['canvasRecording']).toMatchObject({ + enabled: true, + fps: expectedFps, + quality: expectedQuality, + }) } ) }) diff --git a/src/extensions/replay/sessionrecording.ts b/src/extensions/replay/sessionrecording.ts index ee4c2267f..74a6ab050 100644 --- a/src/extensions/replay/sessionrecording.ts +++ b/src/extensions/replay/sessionrecording.ts @@ -74,6 +74,10 @@ const PARTIAL_COMPRESSION_THRESHOLD = ONE_KB export const RECORDING_MAX_EVENT_SIZE = ONE_KB * ONE_KB * 0.9 // ~1mb (with some wiggle room) export const RECORDING_BUFFER_TIMEOUT = 2000 // 2 seconds export const SESSION_RECORDING_BATCH_KEY = 'recordings' +const DEFAULT_CANVAS_QUALITY = 0.4 +const DEFAULT_CANVAS_FPS = 4 +const MAX_CANVAS_FPS = 12 +const MAX_CANVAS_QUALITY = 1 const ACTIVE_SOURCES = [ IncrementalSource.MouseMove, @@ -337,14 +341,21 @@ export class SessionRecording { const canvasRecording_client_side = this.instance.config.session_recording.captureCanvas const canvasRecording_server_side = this.instance.get_property(SESSION_RECORDING_CANVAS_RECORDING) - const enabled = canvasRecording_client_side?.recordCanvas ?? canvasRecording_server_side?.enabled ?? false - const fps = canvasRecording_client_side?.canvasFps ?? canvasRecording_server_side?.fps ?? 0 - const quality = canvasRecording_client_side?.canvasQuality ?? canvasRecording_server_side?.quality ?? 0 + const enabled: boolean = + canvasRecording_client_side?.recordCanvas ?? canvasRecording_server_side?.enabled ?? false + const fps: number = + canvasRecording_client_side?.canvasFps ?? canvasRecording_server_side?.fps ?? DEFAULT_CANVAS_FPS + let quality: string | number = + canvasRecording_client_side?.canvasQuality ?? canvasRecording_server_side?.quality ?? DEFAULT_CANVAS_QUALITY + if (typeof quality === 'string') { + const parsed = parseFloat(quality) + quality = isNaN(parsed) ? 0.4 : parsed + } return { enabled, - fps: clampToRange(fps, 0, 12, 'canvas recording fps'), - quality: clampToRange(quality, 0, 1, 'canvas recording quality'), + fps: clampToRange(fps, 0, MAX_CANVAS_FPS, 'canvas recording fps', DEFAULT_CANVAS_FPS), + quality: clampToRange(quality, 0, MAX_CANVAS_QUALITY, 'canvas recording quality', DEFAULT_CANVAS_QUALITY), } }