Session Replay
Record and replay user sessions to understand how users interact with your application. Debug issues faster by watching exactly what users experienced — self-hosted, with full data ownership.
Overview
Temps session replay captures DOM mutations and user interactions using rrweb, then stores the compressed event stream on your own infrastructure. You retain full control over your users' data — nothing is sent to external services.
What's Recorded
- Full DOM snapshots and incremental mutations
- Mouse clicks, scrolls, and keyboard events
- Page navigations and URL changes
- Viewport and screen dimensions
- Browser, OS, and language metadata
- Session duration and activity state
What's Included
- Complete data ownership — no third parties
- Privacy controls with CSS-selector masking
- Configurable sampling rate
- Path-based exclusion rules
- Automatic 15-day data cleanup
- CLI access to sessions and raw events
Session replay does not capture console logs, network requests, or performance metrics such as FPS or memory usage. It records the visual DOM state and user input events only.
Setup
Session recording is opt-in and disabled by default. Enable it on the provider and pass a sessionRecordingConfig to control behaviour.
React
React Setup
Controlling recording from a component
Use useSessionRecording() inside any component that is already wrapped by TempsAnalyticsProvider (or SessionRecordingProvider):
useSessionRecording hook
import { useSessionRecording } from '@temps-sdk/react-analytics'
export function CookieBanner() {
const { isRecordingEnabled, enableRecording, disableRecording } =
useSessionRecording()
return (
<div>
<p>Session recording is {isRecordingEnabled ? 'on' : 'off'}.</p>
<button onClick={enableRecording}>Allow recording</button>
<button onClick={disableRecording}>Opt out</button>
</div>
)
}
The hook exposes:
| Field | Type | Description |
|---|---|---|
isRecordingEnabled | boolean | Whether recording is currently active |
enableRecording | () => void | Start recording this session |
disableRecording | () => void | Stop recording this session |
toggleRecording | () => void | Toggle recording on/off |
sessionId | string | null | Current rrweb session ID |
If you need recording control without a provider (for example in a standalone component tree), use useSessionRecordingControl(defaultEnabled?) instead — it requires no wrapper.
Svelte
Svelte store
import { sessionRecordingStore } from '@temps-sdk/svelte-analytics'
// Create a store — pass `true` to enable immediately
const recording = sessionRecordingStore(false)
// In response to a user action:
recording.enable()
recording.disable()
recording.toggle()
Vanilla JS
Vanilla JS
<script src="https://cdn.jsdelivr.net/npm/@temps-sdk/browser-analytics/dist/index.js"></script>
<script>
TempsAnalytics.init({
projectId: 'your-project-id',
sessionReplay: {
enabled: true,
sessionSampleRate: 0.5,
maskAllInputs: true,
excludedPaths: ['/checkout/*'],
},
})
</script>
Privacy Controls
Session replay is built on rrweb, which provides fine-grained control over what is — and is not — recorded.
Always redacted
Password inputs (type="password") are always masked by rrweb regardless of configuration. No additional setup is needed.
Mask text in specific elements
Add data-rr-mask to any element whose text content should appear as **** in the replay:
<p data-rr-mask>Sensitive information shown to the user</p>
Or configure a CSS selector to mask all matching elements:
sessionRecordingConfig: {
maskTextSelector: '[data-mask], .pii-field',
}
Block entire elements from recording
Add data-rr-block (or the configured blockClass) to remove an element entirely — it is replaced by a placeholder rectangle in the replay:
<div class="rr-block">
<!-- This element will not appear in the replay at all -->
<img src="/user-photo.jpg" />
</div>
sessionRecordingConfig: {
blockClass: 'rr-block', // default — matches elements with this CSS class
}
Ignore interaction events on an element
Use data-rr-ignore (or ignoreClass) so that clicks and keyboard events on that element are not recorded, while the element's DOM content still appears:
<input class="rr-ignore" placeholder="Untracked field" />
Mask all inputs
Enable maskAllInputs (the default) to replace every input value with * characters across the entire recording. Disable it only if you have verified that no sensitive values flow through your inputs.
sessionRecordingConfig: {
maskAllInputs: true, // default — recommended for all production apps
}
Path-based exclusion
Use excludedPaths with * wildcards to skip recording on specific routes:
sessionRecordingConfig: {
excludedPaths: [
'/admin/*',
'/account/payment',
'/profile/edit',
],
}
GDPR / sampling
Set sessionSampleRate: 0 to record no sessions by default, then call enableRecording() only after users give explicit consent:
// Record zero sessions globally
sessionRecordingConfig={{ sessionSampleRate: 0 }}
// Enable only after consent
const { enableRecording } = useSessionRecording()
<button onClick={enableRecording}>Accept analytics</button>
Geo-based opt-in/opt-out rules are not implemented. Use sessionSampleRate: 0 combined with a consent banner if you need to disable recording for users in specific regions.
Recording Lifecycle
How events are stored
Events are sent to the Temps backend in batches. Each batch is base64 + zlib compressed in transit, then decoded and stored in the session_replay_events table as raw JSON in rrweb format.
The following rrweb event types are captured:
| Type | Constant | Description |
|---|---|---|
0 | DomContentLoaded | Initial DOMContentLoaded event |
1 | Load | Window load event |
2 | FullSnapshot | Complete DOM snapshot |
3 | IncrementalSnapshot | DOM mutations, mouse moves, clicks, scrolls |
4 | Meta | Viewport metadata |
5 | Custom | SDK-defined custom events |
6 | Plugin | Plugin-generated events |
Session metadata
Each session is stored in session_replay_sessions with:
- Browser name and version
- Device type, operating system, and OS version
- Screen and viewport dimensions (width × height)
- Language and timezone
- Entry URL, total duration, and active/idle state
- Project and environment IDs
Batching and flush behaviour
Events are buffered client-side. You can tune both limits:
sessionRecordingConfig: {
batchSize: 100, // send after accumulating this many events (default: 100)
flushInterval: 5000, // or after this many ms, whichever comes first (default: 5000)
}
Lower flushInterval means fewer lost events if a user closes the tab, at the cost of more frequent network requests.
CLI
The Temps CLI provides full access to session replay data for scripting, debugging, and export.
List sessions for a project
bunx @temps-sdk/cli session-replay list \
--project-id <project-id> \
[--environment-id <env-id>] \
[--page <n>] \
[--per-page <n>] \
[--json]
List sessions for a specific visitor
bunx @temps-sdk/cli session-replay visitor <visitor-id> \
[--page <n>] \
[--per-page <n>] \
[--json]
Show session metadata
bunx @temps-sdk/cli session-replay show <visitor-id> <session-id> [--json]
Export raw events
# Print event stream to stdout
bunx @temps-sdk/cli session-replay events <visitor-id> <session-id>
# Write to a file for offline replay or debugging
bunx @temps-sdk/cli session-replay events <visitor-id> <session-id> \
--output session-events.json \
[--page <n>] \
[--limit <n>]
Delete a session
bunx @temps-sdk/cli session-replay delete <visitor-id> <session-id>
# Skip the confirmation prompt (useful in scripts)
bunx @temps-sdk/cli session-replay delete <visitor-id> <session-id> -y
The commands sessions and replay are accepted as aliases for session-replay.
Viewing Replays
Recorded sessions appear in your project dashboard under Analytics → Session Replay. The replay player renders the rrweb event stream and provides:
- Play, pause, and variable-speed playback
- A timeline scrubber with event markers (clicks, navigation, input)
- Session metadata panel (browser, OS, device, screen size, duration)
- Per-session visitor history (all sessions by the same visitor ID)
Sessions are listed in reverse chronological order. Use the environment selector to filter between production, staging, and preview environments.
Data Retention
Session replay data is automatically purged after 15 days by default. This applies to both session metadata (session_replay_sessions) and the associated event stream (session_replay_events).
The retention window is configurable on self-hosted deployments via the Temps server configuration. Reducing the retention period is recommended for GDPR Article 5(1)(e) storage-limitation compliance.
Deleting a session via the CLI or dashboard removes both the session metadata row and all associated events immediately, before the automatic cleanup runs.
Configuration Reference
Full SessionRecordingConfig interface:
| Option | Type | Default | Description |
|---|---|---|---|
sessionSampleRate | number | 1.0 | Fraction of sessions to record. 0.0 = none, 1.0 = all. |
maskAllInputs | boolean | true | Replace all input values with * characters. |
maskTextSelector | string | "[data-mask]" | CSS selector — matching elements have their text replaced with asterisks. |
maskTextClass | string | "rr-mask" | CSS class — elements with this class have text masked. |
blockClass | string | "rr-block" | CSS class — elements with this class are replaced by a placeholder. |
ignoreClass | string | "rr-ignore" | CSS class — interaction events on these elements are not recorded. |
excludedPaths | string[] | [] | URL paths to skip. Supports * wildcards (e.g. "/admin/*"). |
recordCanvas | boolean | false | Capture <canvas> element contents. Increases payload size significantly. |
collectFonts | boolean | false | Inline font files into the recording for accurate replay on other machines. |
batchSize | number | 100 | Number of events to accumulate before flushing to the server. |
flushInterval | number | 5000 | Milliseconds between periodic flushes, regardless of batch size. |
Provider props (React)
| Prop | Type | Default | Description |
|---|---|---|---|
enableSessionRecording | boolean | false | Must be true to activate recording. |
sessionRecordingConfig | SessionRecordingConfig | {} | Recording options — see table above. |