Replay
Replay captures a recording of a user's browser or mobile session and streams it to Sentry in segments. Each segment consists of two envelope items sent together: a replay_event (metadata about the replay) and a replay_recording (the actual recording data). Sentry stitches segments into a continuous replay for debugging.
Related specs:
- Envelopes — transport format
- Envelope Items —
replay_eventandreplay_recordingitem type constraints - Replay Recording Events — recording instruction set format
Replay operates in one of two modes:
- Session mode (
sessionSampleRate) — Recording starts immediately at SDK initialization and streams continuously to Sentry. - Buffer mode (
onErrorSampleRate) — Recording starts at SDK initialization but is buffered in-memory (ring buffer). Capture is only triggered by an error or manual flush.
A replay is composed of segments, each identified by a segment_id (starting at 0). Each segment is sent as a pair of envelope items: a replay_event containing metadata and a replay_recording containing the actual recording data.
When an SDK records Session Replay in session mode (sessionSampleRate is specified), the recording SHOULD start when the SDK is initialized and MUST be continuously streamed to the Sentry servers. SDKs SHOULD send a replay envelope every 5 seconds.
The maximum duration of the recording MUST NOT exceed 60 minutes (or 15 minutes without activity on Web). (since 1.2.0) After the hard limit has been reached, the SDK MUST stop recording, clear the current replay_id, and remove it from the Scope so all subsequent events are not associated with it.
For SDKs that support disk cache, the recording SHOULD pause when there is no internet connection or the SDK is being rate-limited. This prevents overflowing the disk cache, which can result in losing more critical envelopes. When internet connection is restored or the rate limit is lifted, the recording SHOULD resume.
When an SDK records Session Replay in buffer mode (onErrorSampleRate is specified), the recording SHOULD start when the SDK is initialized and MUST be buffered in-memory (and to disk if the SDK supports disk cache) in a ring buffer for up to 30 seconds back.
Capturing of the recording MAY be triggered when one of the following conditions is met:
- A crash or error event occurs and is captured by the SDK.
- The
flushAPI has been called manually on the replay (for SDKs that support manual API).
After the initial (buffered) segment has been captured, the SDK SHOULD continue recording in session mode. The replay_type field of subsequent segments MUST still be set to buffer to reflect the original replay type.
If the crash or error event has been dropped in beforeSend, the replay MUST NOT be captured.
A replay_event Item MUST always be sent together with a replay_recording Item in the same envelope.
| Field | Type | Required | Since | Description |
|---|---|---|---|---|
type | String | REQUIRED | 1.0.0 | MUST be "replay_event". |
replay_id | String | REQUIRED | 1.0.0 | A unique ID for the replay. Follows the same requirements as event_id: hexadecimal UUID v4, exactly 32 characters, lowercase, no dashes. |
replay_type | String | REQUIRED | 1.0.0 | One of "session" or "buffer". Describes the mode of the replay. |
segment_id | Number | REQUIRED | 1.0.0 | The segment identifier, starting at 0. |
replay_start_timestamp | Number | REQUIRED (first segment) | 1.0.0 | UNIX timestamp of the start of the replay (in seconds). Only required on the first segment. |
urls | List[String] | OPTIONAL | 1.0.0 | List of URLs in order of visitation. |
trace_ids | List[String] | OPTIONAL | 1.0.0 | List of trace IDs that occurred during the replay. |
error_ids | List[String] | DEPRECATED | 1.0.0 | Deprecated. Do not use. |
The following attributes are a subset of the optional attributes of an Event.
| Field | Type | Required | Since | Description |
|---|---|---|---|---|
timestamp | Number | REQUIRED | 1.0.0 | UNIX timestamp of the current time (in seconds). |
event_id | String | REQUIRED | 1.0.0 | MUST be the same as replay_id. |
platform | String | OPTIONAL | 1.0.0 | Platform of the SDK. |
environment | String | OPTIONAL | 1.0.0 | The environment name. |
release | String | OPTIONAL | 1.0.0 | The release version. |
dist | String | OPTIONAL | 1.0.0 | The distribution identifier. |
user.id | String | OPTIONAL | 1.0.0 | User identifier. |
user.username | String | OPTIONAL | 1.0.0 | Username. |
user.email | String | OPTIONAL | 1.0.0 | User email. |
user.ip_address | String | OPTIONAL | 1.0.0 | User IP address. |
sdk.name | String | OPTIONAL | 1.0.0 | SDK name. |
sdk.version | String | OPTIONAL | 1.0.0 | SDK version. |
request.url | String | OPTIONAL | 1.0.0 | Current request URL. |
request.headers.User-Agent | String | OPTIONAL | 1.0.0 | User agent string. |
The replay_recording item consists of two sub-items delimited by a newline:
- Metadata — a JSON object. Currently only
segment_idis required:
{ "segment_id": 0 }
- Recording payload — the replay recording instruction set. This payload SHOULD be gzipped, but uncompressed payloads are also accepted. See Replay Recording Events for the recording format.
SDKs MUST accept a replaysSessionSampleRate configuration option (number, 0.0–1.0, default 0). This controls the fraction of sessions recorded in session mode. 1.0 records all sessions, 0 records none.
Naming SHOULD follow the SDK's language conventions:
replaysSessionSampleRate(JavaScript)replays_session_sample_rate(Python)
SDKs MUST accept a replaysOnErrorSampleRate configuration option (number, 0.0–1.0, default 0). This controls the fraction of sessions buffered for error replay. 1.0 captures all sessions with an error, 0 captures none.
Naming SHOULD follow the SDK's language conventions:
replaysOnErrorSampleRate(JavaScript)replays_on_error_sample_rate(Python)
SDKs MUST provide a replay integration that initializes the recording subsystem:
replayIntegration(options?) -> Integration
SDKs MAY accept privacy and configuration options (text masking, media blocking, network capture settings).
Naming SHOULD follow the SDK's language conventions:
replayIntegration()(JavaScript)SessionReplayIntegration()(Python)SentryReplay/SessionReplay(mobile SDKs)
SDKs SHOULD expose a function to retrieve the active replay instance:
getReplay() -> replayInstance | null
Returns the replay integration instance if replay is initialized, or null if not. The returned instance provides the runtime control methods documented below.
The replay instance MUST expose a method to retrieve the current replay identifier:
replayInstance.getReplayId() -> replayId | null
Returns the current replay_id (string) if a replay is active, or null if no replay is recording or buffering. This is useful for checking whether a replay is active before calling other runtime methods.
The replay instance SHOULD expose a method to manually start recording in session mode:
replayInstance.start() -> void
Starts recording in session mode regardless of sample rates. If a session is already running, this SHOULD be a no-op.
The replay instance SHOULD expose a method to manually start recording in buffer mode:
replayInstance.startBuffering() -> void
Starts recording in buffer mode regardless of sample rates. If a session is already running, this SHOULD be a no-op.
The replay instance SHOULD expose a method to stop recording:
replayInstance.stop() -> Promise<void>
Flushes any pending recording data, stops the replay, and ends the session.
The replay instance SHOULD expose a method to flush pending recording data:
replayInstance.flush() -> Promise<void>
In session mode, this uploads pending recording data to Sentry. In buffer mode, this uploads the buffered data and continues recording (same as when an error triggers capture). Calling flush() while replay is stopped MAY start a new session recording.
import * as Sentry from "@sentry/browser";
Sentry.init({
dsn: "https://[email protected]/0",
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
integrations: [Sentry.replayIntegration()],
});
// Manual control
const replay = Sentry.getReplay();
replay.start(); // start session-mode recording
replay.flush(); // flush buffered data
await replay.stop(); // stop and end session
{
"type": "replay_event",
"replay_id": "36b75d9fa11f45459412a96c41bdf691",
"replay_start_timestamp": 1710861499.287,
"replay_type": "session",
"segment_id": 0,
"trace_ids": ["905aef2282af5fe2ab2c93aa7a340521"],
"urls": [
"https://sentry.io/issues/",
"https://sentry.io/issues/?project=0&statsPeriod=7d&utc=true"
],
"request": {
"url": "https://sentry.io/issues/?project=0&statsPeriod=7d&utc=true",
"headers": {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
},
"timestamp": 1710861507.579,
"event_id": "36b75d9fa11f45459412a96c41bdf691",
"environment": "prod",
"release": "frontend@f00",
"sdk": {
"integrations": [
"BrowserTracing",
"BrowserProfiling",
"Replay",
"ReplayCanvas"
],
"name": "sentry.javascript.react",
"version": "7.105.0"
},
"tags": {
"sentry_version": "24.4.0.dev0"
},
"user": {
"ip_address": "127.0.0.1",
"email": "[email protected]",
"id": 1,
"name": "Admin"
},
"contexts": { "organization": { "id": "0", "slug": "sentry" } },
"platform": "javascript"
}
{"segment_id": 0}
\x00\x00\x00\x14ftypqt \x00\x00\x00\x00qt \x00\x00\x00\x08wide\x03\xbdd\x11mdat
{"event_id":"36b75d9fa11f45459412a96c41bdf691","sent_at":"2024-03-19T15:18:27.581Z","sdk":{"name":"sentry.javascript.react","version":"7.105.0"}}
{"type":"replay_event"}
{
"type": "replay_event",
"replay_id": "36b75d9fa11f45459412a96c41bdf691",
"replay_start_timestamp": 1710861499.287,
"replay_type": "session",
"segment_id": 0,
"trace_ids": ["905aef2282af5fe2ab2c93aa7a340521"],
"urls": [
"https://sentry.io/issues/",
"https://sentry.io/issues/?project=0&statsPeriod=7d&utc=true"
],
"request": {
"url": "https://sentry.io/issues/?project=0&statsPeriod=7d&utc=true",
"headers": {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
},
"timestamp": 1710861507.579,
"event_id": "36b75d9fa11f45459412a96c41bdf691",
"environment": "prod",
"release": "frontend@f00",
"sdk": {
"integrations": [
"BrowserTracing",
"BrowserProfiling",
"Replay",
"ReplayCanvas"
],
"name": "sentry.javascript.react",
"version": "7.105.0"
},
"tags": {
"sentry_version": "24.4.0.dev0"
},
"user": {
"ip_address": "127.0.0.1",
"email": "[email protected]",
"id": 1,
"name": "Admin"
},
"contexts": { "organization": { "id": "0", "slug": "sentry" } },
"platform": "javascript"
}
{"type":"replay_recording","length":141666}
{"segment_id":0}
/* gzipped JSON payload */
| Version | Date | Summary |
|---|---|---|
1.2.0 | 2025-07-30 | Added session mode hard limit behavior (stop recording, clear replay_id, remove from scope) |
1.1.0 | 2025-07-29 | Added SDK behavior for session mode and buffer mode |
1.0.0 | 2024-08-15 | Initial spec — replay_event and replay_recording wire format |
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").