skip to content

How do you keep a React Native wallet's card-details screen out of screenshots and screen recordings on Android and iOS?

level: juniorimportance: should knowfreq 36%

answer

  1. React Native core has no prop for it
  2. Android: FLAG_SECURE on the window
  3. one Activity: toggle per screen
  4. iOS: detect capture, hide content
  5. usePreventScreenCapture while mounted

basics

~20 s

On Android, set FLAG_SECURE on the Activity window while the screen is visible, for example with expo-screen-capture's usePreventScreenCapture. iOS has no equivalent public flag, so rely on the library's iOS support, detect screenshots and recording, and hide sensitive content.

solid answer

~50 s

React Native core has no prop for this, so it is native or library work. On **Android**, the window flag `FLAG_SECURE` makes the system refuse screenshots and recordings of the window and blanks it in the recent-apps view. A React Native app usually has one Activity, so the flag covers every screen while it is set: turn it on when the card screen appears and off when it leaves. `expo-screen-capture` does exactly that with `usePreventScreenCapture()`, which protects while the component is mounted, or `preventScreenCaptureAsync()` and `allowScreenCaptureAsync()`. **iOS** has no public flag of that kind; `expo-screen-capture` has implemented screenshot prevention on iOS itself since SDK 54, and the platform lets an app detect screenshots after the fact and detect recording or mirroring so it can hide the numbers. None of this stops a second camera, so keep full card numbers off the screen where you can.

code

tsx · 17 lines
tsx
import { Text, View } from 'react-native';
import { usePreventScreenCapture } from 'expo-screen-capture';

type Props = { last4: string; expiry: string };

export function CardDetailsScreen({ last4, expiry }: Props) {
  // Capture protection is on while this screen is mounted and
  // released when it unmounts, so other screens stay capturable.
  usePreventScreenCapture();

  return (
    <View>
      <Text>Card ending in {last4}</Text>
      <Text>Expires {expiry}</Text>
    </View>
  );
}

go deeper

for a junior

Recall that React Native core has no prop for this: on Android use FLAG_SECURE, usually through expo-screen-capture's usePreventScreenCapture, and treat iOS separately.

for a middle

Explain why the Android flag must be toggled per screen in a single-Activity app, what iOS offers publicly, and why listeners only react after the fact.

for a senior

Combine controls for a real card screen: scoped capture protection, recording and app-switcher hiding, masking with timed reveal, and awareness that rooted devices can defeat all of it.

for a principal

Decide which data the product may display at all, since capture protection only raises effort, and align that with compliance requirements for card data.

## Why this is platform work A mobile-wallet app shows card numbers, balances and one-time codes. Screenshots end up in photo libraries that sync to the cloud, and screen recordings can be made by other apps or shared during a call. React Native renders real native views, so what can be captured is decided by each platform's windowing system, and **React Native core has no prop or API to control it**. You either write a few lines of native code or use a library such as `expo-screen-capture`. ## Android: FLAG_SECURE Android has a window flag, `FLAG_SECURE`, that tells the system to treat the window's content as secure: - screenshots of the window are refused; - screen recording and casting show it as blank; - the recent-apps thumbnail is blanked. Two React Native details matter: 1. **One Activity, many screens.** A React Native app normally renders every screen inside a single Activity, so the flag applies to the whole app while it is set. Turn it on when the card screen gains focus and off when it loses it, or users cannot screenshot anything anywhere. 2. **Library or native code.** `expo-screen-capture` wraps this. `usePreventScreenCapture()` protects "as long as this component is mounted", and `preventScreenCaptureAsync()` with `allowScreenCaptureAsync()` gives manual control. A bare app can set the flag on the Activity window from a small native module instead. ## Bare React Native without a library Without Expo's module, the Android side is a few lines of native code: a small native module with two methods that add or clear `FLAG_SECURE` on the current Activity's window, called from the screen's focus and blur handlers. Window changes must run on the Android UI thread, so the module posts the work there rather than touching the window from the JavaScript thread. The iOS side is harder to write yourself, which is one reason teams adopt a maintained library. ## iOS: no public switch iOS has no public flag equivalent to `FLAG_SECURE`. What the platform offers publicly is **detection**: - a notification after the user **takes a screenshot** — the image already exists; - a way to know the screen is **being captured**, by recording or mirroring, so the app can hide content while it lasts. `expo-screen-capture` added its own screenshot prevention on iOS in SDK 54, so `usePreventScreenCapture()` now covers both platforms in an Expo app; on iOS that protection is implemented by the library rather than by a documented system flag, so test it on each iOS version you support. The system also takes a **snapshot** of the app for the app switcher when it moves to the background. Cover sensitive screens with a neutral view as the app becomes inactive, so the snapshot does not show card details. ## Screenshot listeners `expo-screen-capture` can also report screenshots through `addScreenshotListener()` or the `useScreenshotListener` hook; remove a listener through the subscription it returns. A wallet can use this to warn the user or to log the event. | Android version | Screenshot callback | |---|---| | 14 and later | works without any permission | | 13 and lower | requires `READ_MEDIA_IMAGES`, a broad photo permission with store-policy implications | Blocking capture with `FLAG_SECURE` needs no permission on any version. ## What capture protection does not do - It does not stop a **second phone's camera** pointed at the screen. - On a **rooted** device, tools can clear the flag or read the view hierarchy directly. - It does not protect data the app **logs, caches or sends** elsewhere. So the stronger control is showing less: mask the card number except the last four digits, reveal the full number only after re-authentication and only for a few seconds. ## Testing it The Expo docs give two quick triggers: on the Android Emulator, run `adb shell input keyevent 120` in a terminal to take a screenshot; on the iOS Simulator, use **Device > Trigger Screenshot**. Both exercise listeners and prevention without a physical device, but confirm the final behaviour on real phones, including screen recording and the app switcher. ## Checklist for a card-details screen - Protect capture only while the screen is focused. - Hide content while the screen is being recorded or mirrored, and before the app-switcher snapshot. - Mask by default; reveal briefly after re-authentication. - Test on real devices of both platforms; simulators behave differently.

  • Why does setting FLAG_SECURE once in MainActivity annoy users of a React Native app?
    React Native renders every screen inside that one Activity, so the flag blocks screenshots everywhere, including screens users legitimately want to capture, such as a receipt. Scope it to the sensitive screen, turning it on when that screen is focused and off when it leaves, which is what usePreventScreenCapture does while mounted.
  • Why is a screenshot listener not a substitute for prevention on a card screen?
    The callback fires after the screenshot exists, so the card number is already in the photo library. A listener is useful for warning the user or logging, but only prevention, masking or not rendering the data actually keeps it out of the image.

saying these in an interview costs you the question

  • React Native has a secure prop on View that blocks screenshots.
  • A screenshot listener prevents the screenshot from being saved.
  • FLAG_SECURE also stops someone filming the screen with another phone.
  • iOS offers the same public window flag as Android.
  • Blocking screenshots needs a runtime permission on Android.