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 hitssessionReplayOnErrorSampleRate - 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
manualmode, the business code must also actively callsnapshotCanvas(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.
1. Manual Recording: Most Stable, Most Recommended¶
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:
In this set, what must be explicitly configured is:
sessionReplaySampleRatereplayCanvasEnabled
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: truereplayCanvasMode: 'auto'replayCanvasSampling: 2replayCanvasQuality: '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: truereplayCanvasMode: '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 startedreplayCanvasEnabled: 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: truereplayCanvasMode: '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:
replayCanvasWorkerUrlonly 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:
replayCanvasEnabledreplayCanvasModereplayCanvasSamplingreplayCanvasQualityshouldRecordCanvas
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 callssnapshotCanvas()at appropriate timesauto: SDK automatically captures frames, specific strategy determined byreplayCanvasSampling
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 quality0.25medium: Encoding quality0.4high: Encoding quality0.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:
Or NPM:
The return value is a Promise, which resolves to:
Or:
Current possible reason values include:
not_recordingreplay_disabledinvalid_modenot_canvasnot_serializeddetachedrejected_by_should_record_canvasencode_too_largeunchangedencode_failedobserver_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)
}
})
Recommended Calling Timing¶
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 calledstartSessionReplayRecording()has been calledreplayCanvasEnabled = truereplayCanvasMode = '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 priority0
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:
replayCanvasMimeTypeEncoding format, defaultimage/webpreplayCanvasMaxCanvasSizeMaximum side length allowed before encoding, default1280replayCanvasMaxEncodedBytesMaximum bytes allowed per frame to enter replay, default40000replayCanvasMaxConcurrentEncodesConcurrent encoding limit, default1replayCanvasFlushImmediatelyWhether to prioritize flush after successfully entering replay, defaulttrue
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 demoauto policy: Theinterval / cooldown / unchanged backoff / failure backoff / max per runpassed during demo initializationauto draw: The demo's own continuous redraw switch, only used to create visual changeslast trigger: The source of the most recent manualsnapshotCanvas()triggerlast snapshot: The result of the most recent manualsnapshotCanvas()last reason: The reason for the most recent failureauto result: Strategy result display derived from the current configurationlast 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 changesexport last canvas event: Exports the debug event corresponding to the most recent successful manual snapshot
Note:
auto drawis demo behavior, not the SDK's internal auto samplerauto resultis currently a strategy mapping based on manualsnapshotCanvas()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
replayCanvasEnabledenabled? - Has session replay recording been started?
- Was a
canvaselement 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:
- If the core requirement of the page is "charts should not be missed as much as possible", prioritize using:
- For key charts on the first screen, actively capture a frame after chart rendering is complete:
-
Leave non-critical charts to auto mode
-
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'.