Skip to content

Canvas Recording User Manual (SDK version requirement >= 3.3.0)

Overview

Guance Browser RUM now supports recording canvas content in Session Replay.

First, the most important point:

Configuring replayCanvasEnabled alone is not enough.

For canvas recording to actually take effect, the following prerequisites must also be met simultaneously:

  • Session Replay sampling is enabled
  • That is, sessionReplaySampleRate > 0, or it hits sessionReplayOnErrorSampleRate
  • Session Replay recording has been started
  • That is, startSessionReplayRecording() has been called
  • Canvas recording is enabled
  • That is, replayCanvasEnabled: true
  • The target element on the page is indeed a 2d canvas
  • If in manual mode, the business code must also actively call snapshotCanvas(canvas)

The capability boundaries of the current version are:

  • Supports manual triggering of recording
  • Supports automatic recording
  • Automatic recording supports two formal paths:
  • snapshot sampling
  • higher-fidelity auto recording
  • Only supports 2d canvas
  • Recording results will enter the Session Replay event stream

Areas not covered in the current version:

  • webgl / webgl2
  • Completely consistent restoration for all complex 2D scenarios

Quick Selection

Minimum Viable Configuration

The following three sets are the current minimum viable configurations. For actual integration, it is recommended to copy directly from here and then add more based on the scenario.

This configuration is suitable for:

  • You know when the visual state is stable
  • You only need to capture a frame at key nodes
  • You want to keep costs as controllable as possible
datafluxRum.init({
  applicationId: '<YOUR_APPLICATION_ID>',
  datakitOrigin: '<YOUR_DATAKIT_ORIGIN>',
  sessionReplaySampleRate: 100,

  replayCanvasEnabled: true,
  replayCanvasMode: 'manual',
  replayCanvasQuality: 'medium'
})

datafluxRum.startSessionReplayRecording()

Then actively capture frames in the business code:

await datafluxRum.snapshotCanvas(canvasElement)

In this set, what must be explicitly configured is:

  • sessionReplaySampleRate
  • replayCanvasEnabled

It is recommended to also explicitly configure:

  • replayCanvasMode: 'manual'
  • replayCanvasQuality: 'medium'

2. Auto Snapshot: More Conservative Automatic Recording

This configuration is suitable for:

  • Business logic cannot conveniently manually time frame capture
  • You care more about stability and cost
  • You can accept that automatic frame capture is not frame-by-frame recording
datafluxRum.init({
  applicationId: '<YOUR_APPLICATION_ID>',
  datakitOrigin: '<YOUR_DATAKIT_ORIGIN>',
  sessionReplaySampleRate: 100,

  replayCanvasEnabled: true,
  replayCanvasMode: 'auto',
  replayCanvasSampling: 2,
  replayCanvasQuality: 'medium'
})

datafluxRum.startSessionReplayRecording()

In this set, it is recommended to explicitly configure:

  • replayCanvasEnabled: true
  • replayCanvasMode: 'auto'
  • replayCanvasSampling: 2
  • replayCanvasQuality: 'medium'

If you do not explicitly pass replayCanvasSampling, the SDK will also use the numeric mode, but it is not recommended to rely on default values for integration instructions. It's best to write it clearly.

3. Auto High-Fidelity Recording

This configuration is suitable for:

  • You want the automatic mode to be closer to the real drawing process
  • The page mainly consists of 2D canvas
  • You can accept automatic fallback to snapshot for complex scenarios
datafluxRum.init({
  applicationId: '<YOUR_APPLICATION_ID>',
  datakitOrigin: '<YOUR_DATAKIT_ORIGIN>',
  sessionReplaySampleRate: 100,

  replayCanvasEnabled: true,
  replayCanvasMode: 'auto',
  replayCanvasSampling: 'all',
  replayCanvasQuality: 'medium'
})

datafluxRum.startSessionReplayRecording()

In this set, what must be explicitly configured is:

  • replayCanvasEnabled: true
  • replayCanvasMode: 'auto'
  • replayCanvasSampling: 'all'

What Must Be Configured

If your goal is simply to "get canvas recording running first", you need to care about at least these parameters:

Prerequisites That Must Be Met

  • sessionReplaySampleRate
  • Must ensure replay will be sampled, otherwise canvas recording will not take effect
  • startSessionReplayRecording()
  • init() alone is not enough; replay recording must actually be started
  • replayCanvasEnabled: true
  • Without this, canvas recording is completely disabled

Manual Mode Must Configure

  • replayCanvasEnabled: true
  • It is recommended to explicitly write replayCanvasMode: 'manual'
  • Business code must call snapshotCanvas(canvas)

Auto Mode Must Configure

  • replayCanvasEnabled: true
  • replayCanvasMode: 'auto'
  • It is recommended to explicitly write replayCanvasSampling
  • Numeric value: auto snapshot
  • 'all': higher-fidelity automatic recording

When to Configure replayCanvasWorkerUrl

This parameter is not a "feature switch", but a deployment parameter.

It only needs to be configured in these scenarios:

  • Site CSP does not allow worker-src blob:
  • You want to host the canvas snapshot encoding worker separately
  • You explicitly want canvas encoding not to use inline blob worker

Typical usage:

datafluxRum.init({
  // ...
  replayCanvasEnabled: true,
  replayCanvasMode: 'auto',
  replayCanvasSampling: 2,
  replayCanvasWorkerUrl: '/canvas-worker.js'
})

Note:

  • replayCanvasWorkerUrl only affects canvas snapshot encoding
  • It does not replace the original workerUrl
  • If the current frame does not go through snapshot encoding, the canvas worker will not be used

Mode Differences

manual

Characteristics:

  • Business actively decides when to capture frames
  • No duplicate frame deduplication
  • Most suitable for "capturing a frame at key nodes"

Suitable for:

  • After chart rendering is complete
  • Game settlement page
  • Whiteboard save
  • Taking the final frame after animation ends

auto

Characteristics:

  • SDK automatically captures frames
  • The specific frame capture method is determined by replayCanvasSampling
  • Recording pauses when the page goes into the background and resumes when returning to the foreground
  • Can return a numeric priority via shouldRecordCanvas() to let key canvases be recorded first

Formal semantics of replayCanvasSampling:

  • 2: Recommended default. Auto snapshot, more balanced stability and cost. It is recommended to start here.
  • 1: More frequent auto snapshot, suitable for 2D canvas with denser visual changes, but encoding and reporting costs are higher.
  • Larger numbers: Auto snapshot is sparser, cost is lower, but intermediate changes are more easily lost.
  • 'all': Higher-fidelity automatic recording, trying to preserve the drawing process; may still automatically fall back to snapshot in complex scenarios.

Simple selection advice:

  • Unsure how to configure: First use replayCanvasSampling: 2
  • More concerned about cost: Increase the numeric value
  • More concerned about fidelity: First try 1, then evaluate if 'all' is really needed
  • Only use 'all' when you explicitly accept higher complexity and higher data costs

Suitable for:

  • Business cannot conveniently manually time frame capture
  • The page contains a small to moderate number of 2D canvases
  • Want to balance between cost and fidelity
  • Only need to prioritize recording the key main chart in multi-chart pages

Use Cases

Suitable for these scenarios:

  • Business itself knows when the visual state is stable
  • Need to manually capture a canvas frame after key operations
  • Need Session Replay to be able to restore some 2D canvas visual results

Not suitable for these scenarios:

  • High-frequency animation frame-by-frame recording
  • Complex WebGL scenarios
  • Video-style playback requiring strict restoration of every frame

Enabling Methods

NPM

import { datafluxRum } from '@cloudcare/browser-rum'

datafluxRum.init({
  applicationId: '<YOUR_APPLICATION_ID>',
  datakitOrigin: '<YOUR_DATAKIT_ORIGIN>',
  service: 'browser',
  env: 'production',
  version: '1.0.0',
  sessionSampleRate: 100,
  sessionReplaySampleRate: 100,
  trackUserInteractions: true,

  replayCanvasEnabled: true,
  replayCanvasMode: 'manual',
  replayCanvasQuality: 'medium'
})

datafluxRum.startSessionReplayRecording()

CDN

<script
  src="https://static.guance.com/browser-sdk/v3/dataflux-rum.js"
  type="text/javascript"
></script>
<script>
  window.DATAFLUX_RUM &&
    window.DATAFLUX_RUM.init({
      applicationId: '<YOUR_APPLICATION_ID>',
      datakitOrigin: '<YOUR_DATAKIT_ORIGIN>',
      service: 'browser',
      env: 'production',
      version: '1.0.0',
      sessionSampleRate: 100,
      sessionReplaySampleRate: 100,
      trackUserInteractions: true,

      replayCanvasEnabled: true,
      replayCanvasMode: 'manual',
      replayCanvasQuality: 'medium'
    })

  window.DATAFLUX_RUM && window.DATAFLUX_RUM.startSessionReplayRecording()
</script>

Configuration Item Description

For daily integration, prioritize caring about only the following 5 configurations:

  • replayCanvasEnabled
  • replayCanvasMode
  • replayCanvasSampling
  • replayCanvasQuality
  • shouldRecordCanvas

The remaining parameters belong to advanced overrides. Only continue adjusting them when you have confirmed the default strategy is not suitable for the current page.

replayCanvasEnabled

  • Type: boolean
  • Default: false

Whether to enable canvas recording capability.

It is recommended to always configure this explicitly. When disabled by default, it will not affect existing normal Session Replay logic.

replayCanvasMode

  • Type: string
  • Currently supported: 'manual' | 'auto'
  • Default: 'auto'

Specifies the canvas recording mode.

  • manual: Business code actively calls snapshotCanvas() at appropriate times
  • auto: SDK automatically captures frames, specific strategy determined by replayCanvasSampling

replayCanvasSampling

  • Type: number | 'all'
  • Default: numeric mode

Specifies the canvas recording strategy in auto mode.

  • Numeric value: Uses snapshot sampling
  • 'all': Uses higher-fidelity automatic recording

Recommendation:

  • If the goal is more stable and conservative: Prioritize using numeric mode
  • If the goal is closer to the real drawing process: Use 'all'

Note:

  • 'all' does not mean all scenarios will be recorded via the high-fidelity path
  • For certain complex scenarios, the SDK will automatically fall back to snapshot

replayCanvasQuality

  • Type: 'low' | 'medium' | 'high' | number
  • Default: 0.4

Canvas snapshot encoding quality.

It is recommended to prioritize using preset values:

  • low: Encoding quality 0.25
  • medium: Encoding quality 0.4
  • high: Encoding quality 0.5

These presets mainly affect snapshot encoding quality. Under replayCanvasSampling: 'all', command frames themselves do not go through image encoding, but fallback snapshots will still use the quality configuration here.

If a number is passed, it is still treated as an advanced override.

Higher numeric or preset values mean:

  • Higher image quality
  • Typically larger size
  • Greater pressure on replay segments

It is recommended to start with medium.

How to Record

API

Current public API:

DATAFLUX_RUM.snapshotCanvas(canvasElement)

Or NPM:

datafluxRum.snapshotCanvas(canvasElement)

The return value is a Promise, which resolves to:

{ ok: true }

Or:

{ ok: false, reason: '...' }

Current possible reason values include:

  • not_recording
  • replay_disabled
  • invalid_mode
  • not_canvas
  • not_serialized
  • detached
  • rejected_by_should_record_canvas
  • encode_too_large
  • unchanged
  • encode_failed
  • observer_stopped

Minimal Example

const canvas = document.getElementById('my-canvas')
const ctx = canvas.getContext('2d')

ctx.fillStyle = '#2563eb'
ctx.fillRect(20, 20, 160, 80)
ctx.fillStyle = '#0f172a'
ctx.font = '20px sans-serif'
ctx.fillText('Canvas Replay', 210, 70)

window.DATAFLUX_RUM &&
  window.DATAFLUX_RUM.snapshotCanvas(canvas).then((result) => {
    if (!result.ok) {
      console.warn('snapshotCanvas failed:', result.reason)
    }
  })

It is recommended to call at the following times:

  • After a drawing is complete
  • After a set of animations ends
  • After the user completes a key interaction

Not recommended:

  • Calling every frame
  • Calling in high-frequency timers
  • Large batches of calls outside of page idle times

Recording Activation Conditions

For a canvas snapshot to actually enter replay, all of the following must be met simultaneously:

  • init() has been called
  • startSessionReplayRecording() has been called
  • replayCanvasEnabled = true
  • replayCanvasMode = 'manual' or 'auto'
  • The passed element is an HTMLCanvasElement
  • The node has entered the current DOM snapshot
  • The node is still in the document
  • The encoding result does not exceed the size limit

If any of these conditions is not met, this snapshot will fail or be skipped.

shouldRecordCanvas Usage

shouldRecordCanvas(canvas) can now control both "whether to record" and the priority in auto mode.

Return value rules:

  • Return false: Do not record this canvas
  • Return a number: Use as priority in auto mode, larger numbers have higher priority
  • Return true, undefined, or other non-numeric truthy values: Use default priority 0

Example:

datafluxRum.init({
  replayCanvasEnabled: true,
  replayCanvasMode: 'auto',
  replayCanvasQuality: 'medium',
  shouldRecordCanvas(canvas) {
    if (canvas.dataset.replay === 'off') {
      return false
    }

    if (canvas.dataset.chartRole === 'primary') {
      return 10
    }

    if (canvas.dataset.chartRole === 'secondary') {
      return 5
    }

    return 0
  }
})

This is useful for dashboards:

  • Primary chart recorded first
  • Secondary charts recorded next if budget allows
  • Unrelated small charts or thumbnails can be directly excluded

Advanced Overrides

If the default strategy is insufficient, then consider these underlying parameters:

  • replayCanvasMimeType Encoding format, default image/webp
  • replayCanvasMaxCanvasSize Maximum side length allowed before encoding, default 1280
  • replayCanvasMaxEncodedBytes Maximum bytes allowed per frame to enter replay, default 40000
  • replayCanvasMaxConcurrentEncodes Concurrent encoding limit, default 1
  • replayCanvasFlushImmediately Whether to prioritize flush after successfully entering replay, default true

It is only recommended to adjust these items in the following scenarios:

  • The number of canvases on the page is significantly higher than the default budget
  • Single frame volume is too large, requiring compression of dimensions or byte count
  • You have confirmed through debug results that the current pace is too slow or too fast

Demo Debug Panel

The local demo in this repository includes a canvas debug panel to facilitate observing the current recording pipeline:

  • mode: The canvas recording mode currently used by the demo
  • auto policy: The interval / cooldown / unchanged backoff / failure backoff / max per run passed during demo initialization
  • auto draw: The demo's own continuous redraw switch, only used to create visual changes
  • last trigger: The source of the most recent manual snapshotCanvas() trigger
  • last snapshot: The result of the most recent manual snapshotCanvas()
  • last reason: The reason for the most recent failure
  • auto result: Strategy result display derived from the current configuration
  • last event: The most recent event status recorded on the demo side

The current demo also provides two auxiliary capabilities:

  • toggle auto draw: Periodically redraws the canvas, convenient for observing if auto mode continuously produces changes
  • export last canvas event: Exports the debug event corresponding to the most recent successful manual snapshot

Note:

  • auto draw is demo behavior, not the SDK's internal auto sampler
  • auto result is currently a strategy mapping based on manual snapshotCanvas() results, mainly for debugging and explanation
  • It is not yet directly connected to the SDK's internal auto timed sampling results
  • The exported event is also a debug sample reconstructed by the demo side based on current canvas content, not directly read back from the intake payload

Performance Recommendations

Canvas recording is a high-cost capability; conservative usage is recommended.

Recommended practices:

  • Only call snapshotCanvas() at critical moments
  • Control canvas dimensions
  • Prioritize using replayCanvasQuality: 'low' | 'medium' | 'high'
  • Keep replayCanvasMaxConcurrentEncodes = 1
  • In auto mode, let the quality preset determine the default budget first
  • For dashboard pages, prioritize using shouldRecordCanvas() for key chart filtering and priority sorting

Not recommended:

  • Taking screenshots of high-frequency animations frame-by-frame
  • Frequently calling on oversized canvases
  • Treating canvas recording as the default path

Privacy Statement

Important note:

  • Canvas pixel content is not automatically protected by ordinary DOM masking rules

This means:

  • Text nodes, form nodes, attribute masking rules do not automatically apply to canvas pixels
  • If sensitive information is drawn on the canvas, it may be restored in the replay after recording

Therefore, it is recommended:

  • Only enable recording for canvases that can be publicly replayed
  • Do not call snapshotCanvas() on canvases containing sensitive content such as account numbers, phone numbers, payment information, etc.

FAQ

1. Why is there no visual content in the replay after calling snapshotCanvas()?

Priority checks:

  • Is replayCanvasEnabled enabled?
  • Has session replay recording been started?
  • Was a canvas element passed?
  • Was the call made after the canvas drawing was complete?
  • Was it discarded due to excessive size?

2. Why is auto mode not frame-by-frame recording?

The current version already supports automatic recording, but it is not "frame-by-frame video".

Reasons:

  • Snapshot sampling is essentially still sampling
  • Higher-fidelity automatic recording, while closer to real drawing, is still subject to complex scenario boundaries and automatic fallback constraints
  • Canvas encoding and upload costs are still significantly higher than ordinary DOM replay
  • WebGL and high-frequency animation scenarios are still not suitable for this path

Therefore, the design goal of the current auto mode is:

  • Capture key visual states at lower cost
  • Balance between fidelity and cost
  • Not turn Session Replay into video recording

3. Why is WebGL not supported?

The current version only supports 2D canvas.

WebGL / WebGL2 contexts are more complex; automatic recording and playback require additional handling, to be considered in future versions.

4. Is canvas recording uploaded separately?

No.

In the current version, canvas snapshots are encoded as part of the replay event and share the same upload pipeline with ordinary replay.

5. Why are some charts recorded in the dashboard page while others are not?

Such pages typically have many canvas charts simultaneously. When "some charts are not recorded", the most common reason is not individual chart errors, but:

  • Auto mode may not record all charts in every round
  • Too many charts on the same screen, auto recording budget insufficient
  • Some charts are drawn too early initially and not redrawn later
  • Some complex charts fall back to snapshot in auto high-fidelity mode, incurring higher costs

Priority recommendations:

  1. If the core requirement of the page is "charts should not be missed as much as possible", prioritize using:
replayCanvasEnabled: true,
replayCanvasMode: 'auto',
replayCanvasSampling: 'all'
  1. For key charts on the first screen, actively capture a frame after chart rendering is complete:
await datafluxRum.snapshotCanvas(canvas)
  1. Leave non-critical charts to auto mode

  2. Use shouldRecordCanvas() to increase priority for key charts, or skip unimportant small charts:

shouldRecordCanvas(canvas) {
  if (canvas.dataset.miniChart === 'true') {
    return false
  }

  if (canvas.id === 'main-trend' || canvas.id === 'conversion-funnel') {
    return 10
  }

  return 1
}

If you value stability and cost more than covering all charts:

  • Keep replayCanvasSampling: 2
  • Only manually call snapshotCanvas(canvas) for key charts

If you value coverage more:

  • Try replayCanvasSampling: 'all'
  • Then supplement with manual frame capture for key charts

Simply put:

  • Auto mode is responsible for "trying to record as much as possible"
  • Manual snapshotCanvas(canvas) is responsible for "ensuring key charts are definitely recorded"

Example Scenarios

Business scenarios suitable for direct integration:

  • Record once after chart drawing is complete
  • Record once at the end of a game level
  • Record once before whiteboard save
  • Record once after signature confirmation

A more complete example:

function drawInvoicePreview(canvas, data) {
  const ctx = canvas.getContext('2d')
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  ctx.fillStyle = '#fff'
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  ctx.fillStyle = '#111827'
  ctx.font = '18px sans-serif'
  ctx.fillText('Invoice Preview', 24, 36)
  ctx.fillText('Order: ' + data.orderNo, 24, 72)
  ctx.fillText('Amount: ' + data.amount, 24, 108)
}

function refreshPreview(canvas, data) {
  drawInvoicePreview(canvas, data)
  window.DATAFLUX_RUM &&
    window.DATAFLUX_RUM.snapshotCanvas(canvas)
}

Dashboard scenario example:

datafluxRum.init({
  replayCanvasEnabled: true,
  replayCanvasMode: 'auto',
  replayCanvasSampling: 2,
  replayCanvasQuality: 'medium',
  shouldRecordCanvas(canvas) {
    if (canvas.dataset.miniChart === 'true') {
      return false
    }

    if (canvas.id === 'main-trend' || canvas.id === 'conversion-funnel') {
      return 10
    }

    return 1
  }
})

The semantics of this configuration are:

  • Skip small auxiliary charts
  • Prioritize recording main trend chart and core funnel chart
  • Other ordinary charts are sampled in rotation at the same priority

Recommendations

The recommended usage for the current version can be summarized in one sentence:

  • Treat canvas recording as "key visual state frame supplementation", not as "continuous video recording"

If the business timing is clear, prioritize manual; if it's a multi-chart scenario like a dashboard, then cautiously enable auto, and explicitly choose numeric sampling or 'all'.