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 current version's capability boundaries 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
Scopes not covered in the current version:
webgl/webgl2- Perfectly identical 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 moments
- 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, the configurations that must be explicitly set are:
sessionReplaySampleRatereplayCanvasEnabled
Configurations recommended to be explicitly set simultaneously are:
replayCanvasMode: 'manual'replayCanvasQuality: 'medium'
2. Auto Snapshot: More Conservative Automatic Recording¶
This configuration is suitable for:
- Business logic cannot conveniently manually time frame captures
- 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, configurations recommended to be explicitly set are:
replayCanvasEnabled: truereplayCanvasMode: 'auto'replayCanvasSampling: 2replayCanvasQuality: 'medium'
If you do not explicitly pass replayCanvasSampling, the SDK will also use a numeric mode, but it is not recommended to rely on default values for integration instructions. It's best to write them clearly.
3. Automatic 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, configurations that must be explicitly set are:
replayCanvasEnabled: truereplayCanvasMode: 'auto'replayCanvasSampling: 'all'
What Must Be Configured¶
If your goal is just "to get canvas recording running first", you need to care about at least the following 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)
Automatic Mode Must Configure¶
replayCanvasEnabled: truereplayCanvasMode: 'auto'- It is recommended to explicitly write
replayCanvasSampling - Numeric value: automatic snapshot
'all': higher-fidelity automatic recording
When to Configure replayCanvasWorkerUrl¶
This parameter is not a "feature switch" but a deployment parameter.
It is only needed 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 writing:
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 moments"
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 critical canvases record first
Formal semantics of replayCanvasSampling:
2: Recommended default. Automatic snapshot, more balanced stability and cost. It is recommended to start here.1: More frequent automatic snapshot, suitable for 2D canvases with denser visual changes, but with higher encoding and reporting costs.- Larger numbers: More sparse automatic snapshot, lower cost, but easier to miss intermediate changes.
'all': Higher-fidelity automatic recording, trying to preserve the drawing process; may still automatically fall back to snapshot in complex scenarios.
Simple selection suggestions:
- 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 captures
- The page contains a small to moderate number of 2D canvases
- Want to balance cost and fidelity
- Only need to prioritize recording key main charts in multi-chart pages
Applicable Scenarios¶
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 '@truewatchtech/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 default is off, 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 completely via the high-fidelity path- For some 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 segment
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 operation 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
- Making large batches of calls outside of page idle times
Recording Effectiveness Conditions¶
For 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 are 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 charts record first
- Secondary charts continue recording when 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 page has significantly more canvases 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 used by the current 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 based on 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 whether continuous changes are produced in auto modeexport 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 automatic samplerauto resultis currently based on manualsnapshotCanvas()results for strategy mapping, mainly used for debugging 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 on 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; it is recommended to use it conservatively.
Recommended practices:
- Only call
snapshotCanvas()at critical moments - Control canvas dimensions
- Prioritize using
replayCanvasQuality: 'low' | 'medium' | 'high' - Keep
replayCanvasMaxConcurrentEncodes = 1 - In auto mode, let quality presets 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 very large canvases
- Treating canvas recording as the default path
Privacy Notes¶
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 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 like account numbers, phone numbers, payment information, etc.
Common Questions¶
1. Why is there no visual content in replay after calling snapshotCanvas()?¶
Priority checks:
- Is
replayCanvasEnabledenabled? - Has session replay recording been started?
- Was a
canvaselement passed? - Was it called after the canvas drawing was complete?
- Was it discarded due to excessive size?
2. Why is automatic 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 the real drawing process, is still constrained by complex scenario boundaries and automatic fallback
- 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 automatic 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, requiring additional handling for automatic recording and playback, 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 and some not in a dashboard page?¶
Such pages typically have many canvas charts simultaneously. When "some charts are not recorded", the most common reason is not individual chart errors, but:
- Automatic mode may not record all charts in every round
- Too many charts on the same screen, automatic recording budget insufficient
- Some charts are drawn too early initially and not redrawn later
- Some complex charts fall back to snapshot in automatic high-fidelity mode, incurring higher costs
Priority recommendations for handling:
- If the page's core requirement 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 automatic mode processing
-
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:
- Automatic 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 saving a whiteboard
- 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 charts and core funnel charts
- 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 capture", 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'.