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://eu.amplitude.com as the base URL instead of https://amplitude.com. For example:

  • List session replays: GET https://eu.amplitude.com/api/1/session-replays
  • Get session replay files: GET https://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

NameDescription
start_timeOptional. ISO 8601 string. Lower bound on replay start_time, inclusive. For example, 2024-01-01T00:00:00Z.
end_timeOptional. ISO 8601 string. Upper bound on replay start_time, inclusive. For example, 2024-01-31T23:59:59Z.
amplitude_idOptional. Integer. Filters results to replays belonging to a specific Amplitude user ID. Mutually exclusive with replay_id.
replay_idOptional. String. Filters results to specific replays by ID, in device_id/session_id format. URL-encode the / separator as %2F. Repeat this parameter to request up to 100 replays. Mutually exclusive with amplitude_id and page_token. When you use this parameter, page_size is ignored and next_page_token is always null.
page_sizeOptional. Integer. Number of results per page. Default is 50, maximum is 200. Ignored when replay_id is specified.
page_tokenOptional. String. Opaque pagination cursor from a previous response's next_page_token. Mutually exclusive with replay_id.
sort_orderOptional. String. asc returns oldest replays first (default). desc returns newest replays first. Must be consistent across pages when using page_token.

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"
}
PropertyDescription
session_replaysArray of session replay objects.
session_replays[].replay_idUnique identifier for the replay, in device_id/session_id format. Use this as the replay_id parameter when fetching files.
session_replays[].session_idThe session identifier.
session_replays[].device_idThe device identifier.
session_replays[].amplitude_idThe Amplitude user ID.
session_replays[].start_timeISO 8601 timestamp of when the session started.
session_replays[].end_timeISO 8601 timestamp of when the session ended.
session_replays[].retention_in_daysNumber of days Amplitude retains the replay data.
next_page_tokenOpaque cursor to pass as page_token to retrieve the next page. null when there are no more results.

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

NameDescription
replay_idRequired. String. The replay identifier, in device_id/session_id format. URL-encode the / separator as %2F.
versionOptional. Integer. Recording format version. 2 or 3. Default is 3.
page_sizeOptional. Integer. Number of files per page. Default is 100, maximum is 1000.
page_tokenOptional. String. Opaque pagination cursor from a previous response's next_page_token.

Response

json
{
  "files": [
    "https://s3.amazonaws.com/...presigned-url-1...",
    "https://s3.amazonaws.com/...presigned-url-2..."
  ],
  "next_page_token": "string | null"
}
PropertyDescription
filesArray of presigned S3 URLs. Each URL serves a gzip-compressed JSON array of rrweb events. URLs expire after 15 minutes.
next_page_tokenOpaque cursor to pass as page_token to retrieve the next page. null when there are no more files.

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

CodeDescription
200 OKSuccessful request.
400 Bad RequestInvalid parameter value. Check the error message for details.
401 UnauthorizedMissing or invalid API credentials.
404 Not FoundNo data found for the given replay_id. Amplitude only returns this error on the first page.

Was this helpful?