feat(replay): Add manual replay control API - #5978
Conversation
Expose start, buffering, pause, resume, stop, and flush operations through Sentry.replay(). Keep lifecycle pauses distinct from explicit user pauses. Foregrounding therefore does not resume sensitive-screen recording unexpectedly. Refs JAVA-325 Co-Authored-By: OpenAI Codex <noreply@openai.com>
|
📲 Install BuildsAndroid
|
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| a21e537 | 319.04 ms | 357.04 ms | 38.00 ms |
| 5cdb0b8 | 311.75 ms | 369.08 ms | 57.33 ms |
| b208705 | 315.54 ms | 354.54 ms | 39.00 ms |
| f158a9a | 352.96 ms | 413.17 ms | 60.21 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| a21e537 | 0 B | 0 B | 0 B |
| 5cdb0b8 | 0 B | 0 B | 0 B |
| b208705 | 0 B | 0 B | 0 B |
| f158a9a | 0 B | 0 B | 0 B |
A foreground callback can run before ReplayIntegration registers and initializes its options. Ignore lifecycle callbacks until the integration is enabled to avoid crashing during SDK initialization. Refs JAVA-325 Co-Authored-By: Codex <noreply@openai.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bd1914c. Configure here.
Track whether a buffered replay was started automatically so only automatic buffers apply per-error sampling. Manually started buffers now capture on errors as documented. Refs JAVA-325 Co-Authored-By: Codex <noreply@openai.com>
This reverts commit 8073208. Reason: Match Sentry JavaScript by applying onErrorSampleRate to all buffered replay captures. Refs JAVA-325 Co-Authored-By: Codex <noreply@openai.com>
runningcode
left a comment
There was a problem hiding this comment.
I did a first pass quick review, ping me for a second round.
|
|
||
| override fun onAppForegrounded(startNewSession: Boolean) { | ||
| enqueueOnMainThread { | ||
| if (!isEnabled.get()) { |
There was a problem hiding this comment.
would it make more sense to check this condition before enqueing?
|
|
||
| override fun onAppForegrounded(startNewSession: Boolean) { | ||
| enqueueOnMainThread { | ||
| if (!isEnabled.get()) { |
There was a problem hiding this comment.
would it make more sense to check this condition before enqueing?
| */ | ||
| public interface IReplayApi { | ||
|
|
||
| /** Starts a new replay session. Does nothing if a replay is already being recorded. */ |
There was a problem hiding this comment.
just for my understanding why is start and startBuffering two different calls. Why do we want to start a session separately from Buffering?
| */ | ||
| void startBuffering(); | ||
|
|
||
| /** Stops the current replay. A subsequent {@link #start()} begins a new replay session. */ |
There was a problem hiding this comment.
does this mean the session is stopped or the buffering is stopped or both?
I ask because we have two different start methods but only a single stop/pause which makes it not clear which one the stop stops
| enqueueOnMainThread { | ||
| val current = state.get() | ||
| if (!current.isRecording) { | ||
| startInternal(isFullSession = true) |
There was a problem hiding this comment.
why does flush call startInternal if we're not recording?

Depends on #5965.
📜 Description
Add
Sentry.replay()controls for starting full-session or buffered recording, stopping, pausing, resuming, and flushing.Lifecycle-driven background pauses remain separate from explicit user pauses. Foregrounding resumes only lifecycle-paused recording, so an app can pause replay on sensitive screens without the SDK unexpectedly restarting it. Starting an already-running replay is a no-op; flushing a stopped replay starts a full session, matching the JavaScript SDK. Explicit starts bypass replay sample rates, which continue to control automatic startup.
💡 Motivation and Context
Give Android applications explicit control over Session Replay for opt-in flows and sensitive screens while preserving automatic lifecycle behavior.
Refs JAVA-325
💚 How did you test it?
./gradlew spotlessApply apiDump.sentry-android-coreunit tests: 1,601 tests, 0 failures, 1 skipped.sentry-android-replayunit tests: 252 tests, 0 failures, 1 skipped.📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps