Skip to content

Mobile Replay (Android, Fabric/New Architecture): maskAllText: false silently ignored — replays always fully masked #6122

@johnhenry

Description

@johnhenry

Summary

Setting maskAllText: false (or any of maskAllImages / maskAllVectors: false) on mobileReplayIntegration has no effect when the React Native app uses the New Architecture (Fabric + TurboModules) on Android. Captured replays show all text / images / vectors fully masked regardless of the option value.

Confirmed on-device on @sentry/react-native@7.2.0 (which pulls in sentry-android-replay@8.21.1).

Hypothesis

The v7.5 changelog mentions the experimental Canvas Capture Strategy: "If this strategy is used, all text and images will be masked, regardless of any masking configuration." Our observation is consistent with the SDK selecting Canvas (not PixelCopy) when running on Fabric, which forces the all-mask behavior.

What's missing is either (a) an opt-in to PixelCopy on Fabric or (b) a Canvas implementation that honors maskAllText: false. Either would unblock the use case.

Environment

  • @sentry/react-native: 7.2.0
  • sentry-android-replay: 8.21.1 (transitive)
  • React Native: 0.81.5
  • Fabric: enabled (react_native_context.fabric: true on captured events)
  • TurboModules: enabled
  • JS engine: Hermes
  • Device: Pixel 7, Android 16
  • App built with EAS, expo-dev-client runtime

Reproduction

Sentry.init({
  dsn,
  enableNative: true,
  replaysOnErrorSampleRate: 1.0,
  integrations: [
    Sentry.mobileReplayIntegration({
      maskAllText: false,
      maskAllImages: false,
      maskAllVectors: false,
    }),
  ],
});

// Then trigger an error:
Sentry.captureException(new Error("test"));
  1. Build an APK with Fabric / New Architecture enabled.
  2. Install on Android device, trigger the error.
  3. Open the resulting replay in the Sentry dashboard.
  4. Expected: text content visible in the captured frames.
  5. Actual: all text masked.

What we verified

  1. The merged options reach the bundle correctly: maskAllText: false is present in the JS bundle Metro serves.
  2. RNSentryModuleImpl.java (packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java) reads mobileReplayOptions.maskAllText and calls androidReplayOptions.setMaskAllText(false).
  3. SentryReplayOptions.setMaskAllText(false) (io.sentry:sentry@8.21.1) adds android.widget.TextView to unmaskViewClasses — verified against the published source.
  4. <Text> in RN renders as ReactTextView extends android.widget.TextView, which would match the unmask rule via the Class.superclass walk in ViewHierarchyNode.shouldMask — but only if the view-hierarchy strategy is reading the actual native views (PixelCopy), not screen pixels (Canvas).

So the option flow is correct end-to-end on the SDK; the result mismatch points to the recording strategy.

Asks

  1. Is the Canvas strategy auto-selected on Fabric in 7.x / 8.x? Confirming intent helps us decide whether to upgrade or wait.
  2. Is there a config knob to force PixelCopy on Fabric (Sentry RN init option, gradle property, or replay option)?
  3. Is there a roadmap version where Canvas honors maskAllText: false or PixelCopy works on Fabric?

Happy to provide more diagnostics. Thanks!

Metadata

Metadata

Assignees

No one assigned
    No fields configured for issues without a type.

    Projects

    Status

    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions