Problem Statement
@sentry-internal/replay's public ReplayIntegration.stop() has no way to stop recording without force-flushing the pending replay once recordingMode === 'session':
// packages/replay-internal/src/integration.ts
stop() {
if (!this._replay) {
return Promise.resolve();
}
return this._replay.stop({ forceFlush: this._replay.recordingMode === 'session', reason: 'manual' });
}
The internal Replay.stop({ forceFlush }) method does support disabling the flush, but that option isn't exposed through the public integration API.
This matters for GDPR/consent-gated setups (CookieYes, OneTrust, Usercentrics, custom CMPs, etc.): a common pattern is to keep Sentry.init() running always (so other instrumentation like browser tracing integrations wire up correctly) but gate actual sending behind beforeSend/beforeSendTransaction, and call replay.stop() when the user withdraws consent for session replay / performance monitoring.
beforeSend/beforeSendTransaction don't apply to Replay envelopes, so today the only gate is stop() — and if the user withdraws consent while an errored session has already been promoted to 'session' recording mode, calling stop() immediately force-flushes and sends the pending replay to Sentry after the user revoked consent. There's no public way to just stop recording and discard the buffered segment instead.
The only workaround right now is reaching into the integration's private _replay field to call the internal stop({ forceFlush: false }) directly, which isn't something we want to depend on in production code since it's not part of the public API surface and could change without notice.
Solution Brainstorm
Expose the existing internal forceFlush control on the public integration API, e.g.:
stop(options?: { forceFlush?: boolean }): Promise<void> {
if (!this._replay) {
return Promise.resolve();
}
return this._replay.stop({
forceFlush: options?.forceFlush ?? this._replay.recordingMode === 'session',
reason: 'manual',
});
}
Defaulting to the current behavior (forceFlush: recordingMode === 'session') keeps this fully backwards compatible, while letting consent-driven integrations opt into stop({ forceFlush: false }) to guarantee nothing is sent after withdrawal.
Happy to open a PR for this if the approach looks reasonable — it looks like a small, additive change to packages/replay-internal/src/integration.ts.
Additional Context
Found while implementing consent-mode gating for @sentry/react + @sentry-internal/replay in a web app (browser SDK, @sentry/react@10.53.1). Verified the same limitation is still present as of 10.65.0 (latest at time of writing) — no public API changed in that range.
Problem Statement
@sentry-internal/replay's publicReplayIntegration.stop()has no way to stop recording without force-flushing the pending replay oncerecordingMode === 'session':The internal
Replay.stop({ forceFlush })method does support disabling the flush, but that option isn't exposed through the public integration API.This matters for GDPR/consent-gated setups (CookieYes, OneTrust, Usercentrics, custom CMPs, etc.): a common pattern is to keep
Sentry.init()running always (so other instrumentation like browser tracing integrations wire up correctly) but gate actual sending behindbeforeSend/beforeSendTransaction, and callreplay.stop()when the user withdraws consent for session replay / performance monitoring.beforeSend/beforeSendTransactiondon't apply to Replay envelopes, so today the only gate isstop()— and if the user withdraws consent while an errored session has already been promoted to'session'recording mode, callingstop()immediately force-flushes and sends the pending replay to Sentry after the user revoked consent. There's no public way to just stop recording and discard the buffered segment instead.The only workaround right now is reaching into the integration's private
_replayfield to call the internalstop({ forceFlush: false })directly, which isn't something we want to depend on in production code since it's not part of the public API surface and could change without notice.Solution Brainstorm
Expose the existing internal
forceFlushcontrol on the public integration API, e.g.:Defaulting to the current behavior (
forceFlush: recordingMode === 'session') keeps this fully backwards compatible, while letting consent-driven integrations opt intostop({ forceFlush: false })to guarantee nothing is sent after withdrawal.Happy to open a PR for this if the approach looks reasonable — it looks like a small, additive change to
packages/replay-internal/src/integration.ts.Additional Context
Found while implementing consent-mode gating for
@sentry/react+@sentry-internal/replayin a web app (browser SDK,@sentry/react@10.53.1). Verified the same limitation is still present as of10.65.0(latest at time of writing) — no public API changed in that range.