Session Replay

Session replay is off by default in Temps. Turn it on with enableSessionRecording on the React provider (or data-session-recording="true" on the script tag), and Temps records each session's DOM and user input with rrweb and stores it on your own server. Input values are masked by default.


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.

Replay is part of the same SDK and dashboard as Temps web analytics: pageviews, custom events and Web Vitals are covered in the Analytics docs, and this page owns replay setup. If you are weighing it against a hosted tool, Temps vs FullStory, Temps vs LogRocket and Temps vs PostHog compare features and pricing, and the best self-hosted session replay tools compares the self-hosted options.

What's Recorded

  • Full DOM snapshots and incremental mutations
  • Mouse clicks, scrolls, and input changes (values masked by default)
  • 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. The examples assume the app is deployed on Temps, where the provider's default basePath (/api/_temps) is handled by the proxy; every other provider prop is listed in the React Analytics SDK reference.

React

React Setup

import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics'

export default function RootLayout({ children }) {
  return (
    <TempsAnalyticsProvider enableSessionRecording={true}>
      {children}
    </TempsAnalyticsProvider>
  )
}

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:

FieldTypeDescription
isRecordingEnabledbooleanWhether recording is currently active
enableRecording() => voidStart recording this session
disableRecording() => voidStop recording this session
toggleRecording() => voidToggle recording on/off
sessionIdstring | nullCurrent 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
  defer
  src="https://unpkg.com/@temps-sdk/analytics-browser@0.0.6/dist/temps.min.js"
  data-session-recording="true"
  data-session-sample-rate="0.5"
  data-mask-all-inputs="true"
  data-excluded-paths="/admin/*,/account/*"
></script>

The script tag also skips a built-in list of sign-in, sign-up, password-reset, MFA, checkout, payment and billing paths (/login, /signup, /checkout*, /payment*, /billing* and similar), merged with any data-excluded-paths you add. The React provider applies the same list from @temps-sdk/react-analytics 0.0.7, merged with sessionRecordingConfig.excludedPaths; pass useDefaultExcludedPaths: false to record those routes. Versions 0.0.4 and earlier have no built-in list, so on those pass the routes in excludedPaths yourself.


Privacy Controls

Session replay is built on rrweb, which provides fine-grained control over what is — and is not — recorded.

Always redacted

Password (type="password") and email (type="email") inputs are always masked, even if you turn maskAllInputs off. No additional setup is needed.

Mask text in specific elements

Add data-mask (the default maskTextSelector) or the rr-mask class to any element whose text content should appear as **** in the replay:

<p data-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 the data-private attribute or the rr-block class (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 the data-ignore attribute or the rr-ignore class (the configured ignoreClass) so that input 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',
  ],
}

Leave enableSessionRecording off (the default) and call enableRecording() only after the user gives explicit consent. The choice is saved in localStorage (temps_session_recording_enabled), so returning visitors keep their decision until they call disableRecording():

// Provider: recording stays off until consent
<TempsAnalyticsProvider>{children}</TempsAnalyticsProvider>

// In your consent banner
const { enableRecording } = useSessionRecording()
<button onClick={enableRecording}>Accept session recording</button>

Don't use sessionSampleRate: 0 for this: the sample rate is checked every time recording starts, so a rate of 0 blocks recording even after enableRecording().


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:

TypeConstantDescription
0DomContentLoadedInitial DOMContentLoaded event
1LoadWindow load event
2FullSnapshotComplete DOM snapshot
3IncrementalSnapshotDOM mutations, mouse moves, clicks, scrolls
4MetaViewport metadata
5CustomSDK-defined custom events
6PluginPlugin-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: 10000, // or after this many ms, whichever comes first (default: 10000)
}

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 <project-slug-or-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 Replays. 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. This applies to both session metadata (session_replay_sessions) and the associated event stream (session_replay_events).

The 15-day window is currently fixed and not configurable. If you need a shorter retention period for GDPR Article 5(1)(e) storage-limitation compliance, delete sessions manually via the CLI or dashboard.

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:

OptionTypeDefaultDescription
sessionSampleRatenumber1.0Fraction of sessions to record. 0.0 = none, 1.0 = all.
maskAllInputsbooleantrueReplace all input values with * characters.
maskTextSelectorstring"[data-mask]"CSS selector — matching elements have their text replaced with asterisks.
maskTextClassstring"rr-mask"CSS class — elements with this class have text masked.
blockClassstring"rr-block"CSS class — elements with this class are replaced by a placeholder.
ignoreClassstring"rr-ignore"CSS class — interaction events on these elements are not recorded.
excludedPathsstring[][]URL paths to skip. Supports * wildcards (e.g. "/admin/*"). The script tag adds a built-in list of auth and payment paths; the React provider does not.
recordCanvasbooleanfalseCapture <canvas> element contents. Increases payload size significantly.
collectFontsbooleantrueInline font files into the recording for accurate replay on other machines.
batchSizenumber100Number of events to accumulate before flushing to the server.
flushIntervalnumber10000Milliseconds between periodic flushes, regardless of batch size.

Provider props (React)

PropTypeDefaultDescription
enableSessionRecordingbooleanfalseMust be true to activate recording.
sessionRecordingConfigSessionRecordingConfig{}Recording options — see table above.

Additional Resources

Last updated

Was this page helpful?