iOS: `Sentry.Unmask` / `Sentry.Mask` ignored when replay is started manually with both sample rates at 0

Open Beginner friendly
#6,996 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
76/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
ios, objective-c, react-native, typescript

Research direction

Start in RNSentryStart.m and inspect the replay initialization guard described in the issue; then read RNSentryReplay postInit to confirm what it registers. The reported fix is to call postInit whenever replay is supported, even when both sample rates are zero. Done means manual replay preserves the behavior of Sentry.Unmask and Sentry.Mask on iOS under those settings.

Written by the indexing model from the issue text.

Description

React-Native
What React Native libraries do you use?

Expo (SDK 57, CNG / expo prebuild), Expo Router, React Native 0.86 (New Architecture), Hermes.

Are you using sentry.io or on-premise?

sentry.io (SaaS, EU region)

@sentry/react-native SDK Version

8.33.0 (sentry-cocoa 9.32.0). The same condition is still present in 8.34.0 and on main.

How does your development environment look like?
@sentry/react-native  8.33.0
sentry-cocoa          9.32.0 (prebuilt xcframework)
react-native          0.86.3, New Architecture enabled
expo                  57
iOS                   TestFlight build, iPhone
Sentry.init()
Sentry.init({
  dsn: '...',
  sendDefaultPii: false,
  // Replay is only recorded on one screen, started and stopped manually
  // (Sentry.getReplay().start() / stop(), available since 8.27).
  replaysSessionSampleRate: 0,
  replaysOnErrorSampleRate: 0,
  integrations: [
    Sentry.mobileReplayIntegration({
      maskAllText: true,
      maskAllImages: true,
      maskAllVectors: true,
    }),
  ],
});

// Later, on the screen we want to record (with user consent):
Sentry.getReplay()?.start();
Steps to Reproduce
  1. Initialize the SDK with replaysSessionSampleRate: 0 and replaysOnErrorSampleRate: 0, and mobileReplayIntegration({ maskAllText: true }).
  2. Wrap a static label in <Sentry.Unmask><Text>Continue</Text></Sentry.Unmask>.
  3. Start the replay manually with Sentry.getReplay().start() and navigate the screen.
  4. Open the replay in Sentry.
Expected Result

The Text wrapped in Sentry.Unmask is visible in the replay, as it is on Android and as it is on iOS when a sample rate is positive. Sentry.Mask masks its subtree.

Actual Result

On iOS, the whole replay is masked: Sentry.Unmask has no effect (and Sentry.Mask is not registered either). Android is fine.

Cause

RNSentryStart.m only registers the replay container classes when a sample rate is positive:

[SentrySDK startWithOptions:options];

#if SENTRY_TARGET_REPLAY_SUPPORTED
    if (options.sessionReplay.sessionSampleRate > 0
        || options.sessionReplay.onErrorSampleRate > 0) {
        [RNSentryReplay postInit];
    }
#endif

+[RNSentryReplay postInit] is what calls setReplayRedactContainerClass: (RNSentryReplayMask), setReplayIgnoreContainerClass: (RNSentryReplayUnmask) and configures the RN breadcrumb converter. Since 8.27, a replay can be started manually with both rates at 0, and sentry-cocoa 9.32.0 always installs SentrySessionReplayIntegration on iOS, whatever the rates. The replay therefore records, but without the container classes: Unmask is ignored, Mask is not applied as a container, and replay breadcrumbs go through the default converter instead of RNSentryReplayBreadcrumbConverter.

Raising a rate is not a workaround for us: it would record (or buffer) replays outside the screen the user consented to, without the on-screen recording indicator we show (App Store Review Guideline 2.5.14).

Suggested fix

Call postInit whenever the replay is supported, regardless of the sample rates:

#if SENTRY_TARGET_REPLAY_SUPPORTED
    [RNSentryReplay postInit];
#endif

postInit does not start any recording: it only registers the two container classes and the breadcrumb converter on the installed integration (SentryInternalReplayApi calls are no-ops if the integration is missing). We apply exactly this change at prebuild time as a local workaround.

Dominant language
TypeScript
Stars
1.8k
Forks
373
Avg merge
1d 7h
Merged PRs (30d)
105

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from getsentry/sentry-react-native

All issues in getsentry/sentry-react-native

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.