Skip to content

feat(session-replay-browser): expose start and stop recording APIs - #1949

Merged
jxiwang merged 7 commits into
mainfrom
cursor/session-replay-start-stop-ddae
Aug 27, 2026
Merged

jxiwang merged 7 commits into
mainfrom
cursor/session-replay-start-stop-ddae

Conversation

@jxiwang

@jxiwang jxiwang commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Exposes start() and stop() on the Session Replay browser SDK so customers can pause and resume capture without tearing down the SDK.

  • Standalone (@amplitude/session-replay-browser): sessionReplay.stop() / sessionReplay.start()
  • Plugin (@amplitude/plugin-session-replay-browser): methods on the plugin instance
  • Unified: available via client.sessionReplay().start() / .stop() because that client already returns AmplitudeSessionReplay

stop() cancels the live rrweb recorder (it does not keep observing the DOM), flushes already-captured events, and keeps session id, config, and page listeners in place. start() begins a new rrweb recording. Sampling, targeting, opt-out, and remote captureEnabled still apply. Focus and targeting paths will not auto-restart recording after stop().

In-flight _recordEvents() that already passed getShouldRecord() is abandoned after stop() / shutdown(), so a paused session cannot resume from a stale record() call.

In coordinated cross-origin child iframes, init() still waits for a parent start signal, but a customer start() self-starts capture so resume does not hang if the parent is already recording.

This matches the start/stop API already present on the React Native Session Replay SDK. shutdown() remains the way to fully discontinue collection and remove listeners.

Coverage:

  • Unit tests for start/stop, including that stop() invokes the cancel callback returned by rrweb record(), and that stop() during an in-flight recordEvents() does not start rrweb
  • Child iframe start() after stop() self-starts without a parent signal
  • Playwright e2e in packages/session-replay-browser/e2e/start-stop.spec.ts that mutates the DOM against a live recorder and asserts mutations after stop() never reach the track API

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: no
Open in Web Open in Cursor 

Allow customers to pause and resume session replay capture without
tearing down the SDK. start/stop are available on the standalone
browser SDK, the analytics plugin, and the unified client.

Co-authored-by: Jesse Wang <jxiwang@users.noreply.github.com>
@jxiwang
jxiwang marked this pull request as ready for review August 21, 2026 18:21
@jxiwang
jxiwang requested a review from a team as a code owner August 21, 2026 18:21
@github-actions

github-actions Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

size-limit report 📦

Path Size
packages/analytics-browser/lib/scripts/amplitude-min.js.gz 64.33 KB (0%)
packages/session-replay-browser/lib/scripts/session-replay-browser-min.js.gz 135.3 KB (+0.25% 🔺)
packages/unified/lib/scripts/amplitude-min.umd.js.gz 218.72 KB (+0.14% 🔺)
@amplitude/element-selector (gzipped esm) 3.4 KB (0%)

Comment thread packages/session-replay-browser/src/session-replay.ts
@github-actions

github-actions Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

Session Replay Browser E2E Results

passed  156 passed
flaky  1 flaky

Details

stats  157 tests across 18 suites
duration  4 minutes, 29 seconds
commit  a507e88

Flaky tests

chromium › e2e/cross-origin-iframe.spec.ts › cross-origin iframe recording › coordinator sends start signal to dynamically-added child iframe

cursoragent and others added 2 commits August 21, 2026 18:34
Add Playwright tests that mutate the DOM against a live rrweb recorder
to prove stop() actually cancels capture and start() resumes it. Also
assert the unit path invokes the cancel callback returned by record().
Abort _recordEvents after each await if stop() or shutdown() ran, so a
start that already passed getShouldRecord cannot call rrweb record()
after the customer paused capture.

Co-authored-by: Jesse Wang <jxiwang@users.noreply.github.com>
Comment thread packages/session-replay-browser/src/session-replay.ts
Ensure stop() during initializeNetworkObservers does not start rrweb, and
that a child iframe onStart after stop() is ignored.
Coordinated iframe children wait for a parent start signal on init.
After a customer stop()/start() the parent may already be recording and
will not send another signal, so start() now begins child recording
immediately while still listening for later parent stop/start.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit 3d36667. Configure here.

Comment thread packages/session-replay-browser/src/session-replay.ts Outdated
A gated start() was clearing startChildRecordingOnSetup before
getShouldRecord() could fail, so coordinated child iframes waited
forever for a parent signal that would never be resent.
Properties can become true as soon as targeting matches, before rrweb
events are in the current sequence. flush() only drains the track
destination, so a one-shot blur plus polling flush() never sends.
@jxiwang
jxiwang merged commit 3ac99c3 into main Aug 27, 2026
17 checks passed
@jxiwang
jxiwang deleted the cursor/session-replay-start-stop-ddae branch August 27, 2026 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants