Skip to content

fix(replay): stop touch tracker when session replay is paused#8456

Open
tsushanth wants to merge 1 commit into
getsentry:mainfrom
tsushanth:fix/pause-touch-tracking-clean
Open

fix(replay): stop touch tracker when session replay is paused#8456
tsushanth wants to merge 1 commit into
getsentry:mainfrom
tsushanth:fix/pause-touch-tracking-clean

Conversation

@tsushanth

Copy link
Copy Markdown
Contributor

Summary

SentryTouchTracker.trackTouchFrom was called unconditionally from the sendEvent swizzle regardless of replay pause state. Calling SentrySDK.replay.pause() stopped the capture scheduler (no new screenshots) but left the touch tracker running, so touches continued to buffer and could appear in replay segments captured during/after the pause (e.g. triggered by an error capture).

Changes

  • Add var isEnabled = true to SentryTouchTracker; gate trackTouchFrom on it
  • In SentrySessionReplay.pause(): set touchTracker?.isEnabled = false alongside stopCaptureScheduler()
  • In SentrySessionReplay.resume(): set touchTracker?.isEnabled = true when the capture scheduler successfully restarts

Tests

Two new unit tests in SentryTouchTrackerTests:

  • testIsEnabledFalse_DropsAllTouches — verifies no events recorded when disabled
  • testIsEnabledToggle_OnlyRecordsTouchesWhileEnabled — verifies only touches while enabled appear in replay events

Fixes #8409

#skip-changelog

SentryTouchTracker.trackTouchFrom was called unconditionally from
the sendEvent swizzle regardless of replay pause state. Calling
SentrySDK.replay.pause() stopped the capture scheduler (no new
screenshots) but left the touch tracker running, so touches
continued to buffer and appeared in replay segments produced during
or after the pause (e.g. triggered by an error capture).

Add isEnabled to SentryTouchTracker and gate trackTouchFrom on it.
Set isEnabled = false in SentrySessionReplay.pause() alongside
stopCaptureScheduler(), and restore it to true when the capture
scheduler successfully restarts in resume().

Fixes getsentry#8409

@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 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 73240d5. Configure here.

public func pause() {
SentrySDKLog.debug("[Session Replay] Pausing session")
stopCaptureScheduler()
touchTracker?.isEnabled = false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Touches stay disabled after restart

High Severity

pause() sets isEnabled to false on the shared touchTracker, but only resume() turns it back on. start() reuses that same tracker without resetting isEnabled, so after stop()/start(), session rotation, or max-duration end, touch capture can stay off for the rest of the process unless a later resume() happens to run.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 73240d5. Configure here.

guard let self = self else { return }

if self.startCaptureScheduler(expectedGeneration: schedulerGeneration) {
self.touchTracker?.isEnabled = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Resume race re-enables paused touches

Medium Severity

resume() sets touchTracker?.isEnabled = true only after startCaptureScheduler returns, with no generation or running-state check in between. A concurrent pause() can stop the scheduler and clear isEnabled, then the queued main-thread resume still flips isEnabled back on, so touches keep buffering while capture stays paused.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 73240d5. Configure here.

public func pause() {
SentrySDKLog.debug("[Session Replay] Pausing session")
stopCaptureScheduler()
touchTracker?.isEnabled = false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The touchTracker.isEnabled property is not reset to true when a new session starts, causing touch events to be dropped if the app remains in the foreground.
Severity: HIGH

Suggested Fix

The SentrySessionReplay.start() method should explicitly set touchTracker?.isEnabled = true to ensure the touch tracker is active at the beginning of every new session replay.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift#L236

Potential issue: The `touchTracker.isEnabled` property is set to `false` within the
`pause()` method, which is called when a session replay is stopped. When a new session
starts via `SentrySessionReplay.start()`, this property is not reset to `true`.
Consequently, if a session ends and a new one begins while the app remains in the
foreground, the touch tracker stays disabled for the entire new session, causing all
touch events to be silently ignored. This state only corrects itself if the app is
backgrounded and then foregrounded, which triggers the `resume()` method.

Did we get this right? 👍 / 👎 to inform future reviews.

@NinjaLikesCheez

Copy link
Copy Markdown
Member

Thanks for fixing the formatting issues! :) Our normal way of working is to open PRs as drafts, then address the bot comments + CI (you can ping me to kick it off) - once that's done, you can move it to ready and request a review from the team.

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.

Paused replay still capturing touches

2 participants