Skip to main content

Overview

The Session Replay API handles uploading and retrieving session recordings. Replays are captured by the browser SDK using rrweb and sent to Proliferate when an error occurs.

Authentication

Replay ingestion uses API key in payload authentication. Replay retrieval uses session-based authentication. See Authentication for details.

Upload Session Replay

Upload a complete session replay associated with an error event.
curl -X POST https://api.proliferate.com/api/v1/replays \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "pk_abc123def456ghi789",
    "session_id": "sess_abc123def456",
    "window_id": "win_xyz789abc012",
    "error_event_id": "evt_error123",
    "start_timestamp": 1736938000000,
    "end_timestamp": 1736938300000,
    "duration_ms": 300000,
    "event_count": 1542,
    "total_bytes": 524288,
    "has_full_snapshot": true,
    "events": [
      {
        "type": 2,
        "data": { "node": {...} },
        "timestamp": 1736938000123
      },
      {
        "type": 3,
        "data": { "source": 0, "positions": [...] },
        "timestamp": 1736938001456
      }
    ]
  }'

Endpoint

POST /api/v1/replays

Request Schema

api_key
string
required
Your project API key (format: pk_...)
session_id
string
required
Session identifier (generated by SDK)
window_id
string
required
Window identifier for multi-tab tracking
error_event_id
string
required
Event ID of the error that triggered this replay
start_timestamp
integer
required
Start timestamp in milliseconds (Unix epoch)
end_timestamp
integer
required
End timestamp in milliseconds (Unix epoch)
duration_ms
integer
required
Total duration in milliseconds
event_count
integer
required
Number of rrweb events
total_bytes
integer
required
Total size in bytes
has_full_snapshot
boolean
default:true
Whether the replay contains a full DOM snapshot (required for playback)
events
array
required
Array of rrweb events (DOM snapshots, mutations, interactions)

Response

Success (202 Accepted):
{
  "status": "ok",
  "replay_id": 123
}
Error (401 Unauthorized):
{
  "detail": "Invalid API key"
}
Error (400 Bad Request):
{
  "status": "error",
  "error": "Replay must contain at least one full snapshot for playback"
}

Upload Chunked Replay

For large replays, the SDK splits the data into chunks and uploads them separately.
curl -X POST https://api.proliferate.com/api/v1/replays/chunk \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "pk_abc123def456ghi789",
    "session_id": "sess_abc123def456",
    "window_id": "win_xyz789abc012",
    "error_event_id": "evt_error123",
    "chunk_index": 0,
    "total_chunks": 3,
    "events": [...],
    "metadata": {
      "start_timestamp": 1736938000000,
      "end_timestamp": 1736938300000,
      "duration_ms": 300000,
      "total_event_count": 4500,
      "total_bytes": 2097152,
      "has_full_snapshot": true
    }
  }'

Endpoint

POST /api/v1/replays/chunk

Request Schema

api_key
string
required
Your project API key
session_id
string
required
Session identifier
window_id
string
required
Window identifier
error_event_id
string
required
Error event ID
chunk_index
integer
required
Zero-based index of this chunk (0, 1, 2, …)
total_chunks
integer
required
Total number of chunks
events
array
required
rrweb events for this chunk
metadata
object
Full replay metadata (required on first chunk, chunk_index=0)

Response

Chunk Received (202 Accepted):
{
  "status": "ok"
}
All Chunks Complete (202 Accepted):
{
  "status": "ok",
  "replay_id": 123
}
When all chunks are received, the replay is assembled and stored.

Get Replay by ID

Retrieve a session replay by its ID.
GET /api/v1/replays/{replay_id}
Response:
{
  "id": 123,
  "session_id": "sess_abc123def456",
  "window_id": "win_xyz789abc012",
  "error_event_id": "evt_error123",
  "start_timestamp": "2025-01-15T10:00:00.000Z",
  "end_timestamp": "2025-01-15T10:05:00.000Z",
  "duration_ms": 300000,
  "event_count": 1542,
  "has_full_snapshot": true,
  "storage_size_bytes": 524288,
  "created_at": "2025-01-15T10:05:15.123Z",
  "events_url": "https://s3.amazonaws.com/...",
  "events": []
}
Newer replays are stored in S3 and provide an events_url for efficient fetching. Older replays may have events stored inline.

Get Replay for Error Event

Retrieve the session replay associated with a specific error event.
GET /api/v1/events/{event_id}/replay
Response: Same schema as “Get Replay by ID”, or null if no replay exists for this error.
{
  "id": 123,
  "session_id": "sess_abc123def456",
  ...
}

List Replays for Project

List all replays for a project.
GET /api/v1/projects/{project_id}/replays?limit=50&offset=0
Query Parameters:
limit
integer
default:50
Max replays to return
offset
integer
default:0
Pagination offset
Response:
{
  "replays": [
    {
      "id": 123,
      "session_id": "sess_abc123def456",
      "window_id": "win_xyz789abc012",
      "error_event_id": "evt_error123",
      "start_timestamp": "2025-01-15T10:00:00.000Z",
      "end_timestamp": "2025-01-15T10:05:00.000Z",
      "duration_ms": 300000,
      "event_count": 1542,
      "has_full_snapshot": true,
      "storage_size_bytes": 524288,
      "created_at": "2025-01-15T10:05:15.123Z"
    }
  ],
  "total": 1
}

How Replays Work

1

SDK Starts Recording

The browser SDK uses rrweb to record DOM snapshots and mutations in a ring buffer
2

Error Occurs

When an error is captured, the SDK packages the recent replay events
3

Upload Triggered

The replay is uploaded along with (or immediately after) the error event
4

Stored for Playback

The replay is stored in S3 (or database for small replays) and linked to the error
5

View in Dashboard

View the error in the dashboard and watch the replay to see what happened

rrweb Event Types

Replays use rrweb’s event format:
TypeDescription
0DOM Content Loaded
1Load
2Full Snapshot
3Incremental Snapshot (mutations)
4Meta (viewport, timestamp)
5Custom Event
Full Snapshot (type 2) is required for playback. It captures the complete DOM state at a point in time.

Ring Buffer

The SDK maintains a ring buffer of replay events:
  • Max time: Default 5 minutes
  • Max events: Default 10,000 events
  • Max size: Default 5MB
Older events are dropped as new ones arrive. When an error occurs, the buffer contains the most recent activity leading up to the error.

Storage

  • Small replays (under 1MB): Stored inline in PostgreSQL
  • Large replays (over 1MB): Stored in S3, retrieved via presigned URL
When fetching a replay:
  1. Check if events_url is present
  2. If yes, fetch events from the presigned URL
  3. If no, use the inline events array

Privacy Considerations

Replays respect privacy settings configured in the SDK:
  • Inputs masked by default: Input values are replaced with ***
  • Block elements: Elements with blockClass are not recorded
  • Mask text: Elements with maskTextClass have text replaced
  • Canvas recording disabled: Canvas elements are not captured by default
See SDK configuration for privacy options.

Best Practices

Enable Selectively

Only enable session replay for errors, not all sessions:
Proliferate.init({
  replay: {
    enabled: true, // Record in ring buffer
    // Only sent when error occurs
  },
});

Respect Privacy

Configure privacy settings appropriately:
Proliferate.init({
  replay: {
    maskAllInputs: true,
    blockClass: 'sensitive-data',
    recordCanvas: false,
  },
});

Monitor Buffer Size

Large ring buffers consume memory. Adjust based on your needs:
Proliferate.init({
  replay: {
    maxBufferMinutes: 3,      // Shorter time window
    maxBufferEvents: 5000,    // Fewer events
    maxBufferBytes: 2097152,  // 2MB max
  },
});

Test Playback

Verify replays work correctly:
  1. Trigger a test error
  2. View the error in the dashboard
  3. Watch the replay to ensure it captured the expected activity

Testing

Trigger a test error with replay:
// Perform some actions
document.querySelector('#button').click();
await fetch('/api/data');

// Trigger error (replay will be sent)
throw new Error('Test error with replay');
Check the error in the dashboard and verify the replay shows your actions.