On this page

Session Replay API

Authentication and request requirements

  • All endpoints use HTTP Basic auth. Use your project's API key as the username and secret key as the password.
  • The project_id parameter isn't needed. The authenticated API key identifies the project.
  • Presigned file URLs expire after 15 minutes.
  • Pagination cursors are opaque strings. Don't construct or modify them. Pass next_page_token from the previous response as-is.
  • The sort_order parameter must be consistent across all pages of a paginated request. Passing a page_token from an asc request with sort_order=desc returns a 400 error.
  • amplitude_id and replay_id are mutually exclusive. Passing both returns a 400 error.
  • replay_id and page_token are mutually exclusive. Passing both returns a 400 error.
  • Each replay_id value must use device_id/session_id format. A leading or trailing slash returns a 400 error.
  • You can pass up to 100 replay_id values per request. Passing 101 or more returns a 400 error.
  • amplitude_id must be a valid integer. A non-numeric value returns a 400 error.
  • When you use replay_id, the API ignores page_size and always returns next_page_token as null.

EU data residency

For EU data residency, use https://analytics.eu.amplitude.com as the base URL instead of https://amplitude.com. For example:

  • List session replays: GET https://analytics.eu.amplitude.com/api/1/session-replays
  • Get session replay files: GET https://analytics.eu.amplitude.com/api/1/session-replays/files

List session replays

Returns a paginated list of session replays for the authenticated project.

GET https://amplitude.com/api/1/session-replays

curl
curl --location 'https://amplitude.com/api/1/session-replays' \
-u '{api_key}:{secret_key}'

Query parameters

Response

json
{
  "session_replays": [
    {
      "replay_id": "string",
      "session_id": "string",
      "device_id": "string",
      "amplitude_id": 123456,
      "start_time": "2024-01-01T00:00:00Z",
      "end_time": "2024-01-01T00:05:00Z",
      "retention_in_days": 90
    }
  ],
  "next_page_token": "string | null"
}

Get session replay files

Returns a paginated list of presigned S3 URLs for the event files belonging to a specific replay. Each URL points to a gzip-compressed JSON array of rrweb events. Amplitude orders files by key, which encodes start time.

GET https://amplitude.com/api/1/session-replays/files

curl
curl --location 'https://amplitude.com/api/1/session-replays/files?replay_id={device_id}%2F{session_id}' \
-u '{api_key}:{secret_key}'

Query parameters

Response

json
{
  "files": [
    "https://s3.amazonaws.com/...presigned-url-1...",
    "https://s3.amazonaws.com/...presigned-url-2..."
  ],
  "next_page_token": "string | null"
}

Decompress and parse replay files

The format of each file depends on the version you requested.

Version 3

Each file uses gzip compression. Decompress the file to get a JSON array of rrweb events ready to pass to an rrweb player.

javascript
async function fetchReplayEvents(fileUrl) {
  const response = await fetch(fileUrl);
  // The response is gzip-compressed; fetch decompresses automatically in browsers.
  // In Node.js 18+, use the DecompressionStream API or the zlib module.
  const buffer = await response.arrayBuffer();
  const text = new TextDecoder().decode(buffer);
  return JSON.parse(text); // array of rrweb events
}

The result is a JSON array of rrweb events:

json
[
  { "type": 4, "data": { "href": "https://example.com", "width": 1440, "height": 900 }, "timestamp": 1700000000000 },
  { "type": 2, "data": { ... }, "timestamp": 1700000000050 },
  ...
]

Version 2

Version 2 files require two decompression steps:

  1. gzip decompress the file, then JSON parse → array of packed strings.
  2. zlib decompress each string: each element is a JSON-encoded, zlib-compressed (DEFLATE) binary payload → rrweb event object.
javascript
const zlib = require("zlib");

async function fetchReplayEventsV2(fileUrl) {
  const response = await fetch(fileUrl);
  const buffer = Buffer.from(await response.arrayBuffer());

  // Step 1: gzip decompress the file, then JSON parse → array of packed strings
  const packedStrings = JSON.parse(zlib.gunzipSync(buffer).toString("utf8"));

  // Step 2: unpack each string
  return packedStrings.map((packed) => {
    // Each packed string is itself a JSON string whose value is a latin1-encoded
    // binary blob of zlib-compressed event data.
    const compressedBinary = JSON.parse(packed);
    const buf = Buffer.from(compressedBinary, "latin1");
    return JSON.parse(zlib.inflateSync(buf).toString("utf8")); // rrweb event
  });
}

Play back events

To replay a full session, fetch all files for a replay in order, unpack each file, concatenate the event arrays, and pass the result to Amplitude's rrweb player. Use Amplitude's fork rather than upstream rrweb, because the fork includes fixes that may be incompatible with the upstream version.

javascript
const events = (await Promise.all(fileUrls.map(fetchReplayEvents))).flat();
rrweb.replay({ events, root: document.getElementById("player") });

Status and error codes

Was this helpful?