secure_text_widget
A Flutter widget that renders text so it is excluded from iOS screenshots,
screen recordings, AirPlay mirroring and the App Switcher preview — while
staying a normal-looking Text in the UI.
See it in action
| What the user sees on screen | What actually lands in the screenshot |
|---|---|
![]() |
![]() |
SecureText renders the value normally, like any Text. |
The same SecureText is completely blank in the capture. |
How it works
Flutter draws everything through its own engine (Skia/Impeller), so no
Flutter widget can be selectively hidden from iOS screen capture. To get
around that, SecureText:
- Embeds a real native
UIViewin the Flutter tree viaUiKitView. - That view hosts a hidden
UITextFieldwithisSecureTextEntry = true. - A
UILabelis inserted into the text field's private secure canvas (_UITextLayoutCanvasView). iOS automatically masks the contents of that canvas out of any screen-capture pipeline.
No private APIs are called — only the private subview hierarchy is walked, and this has been stable across iOS 13 → 26.
Usage
import 'package:secure_text_widget/secure_text_widget.dart';
SecureText(
'4242 4242 4242 4242',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w600),
)
The API mirrors Text: data, style, textAlign, maxLines,
textDirection, softWrap. Layout matches what a plain Text would
produce (text is measured with a TextPainter and the native view is
pinned to that box).
Style updates flow through a per-view MethodChannel — changing data,
style or textAlign does not recreate the native view, so there is
no flicker.
Platform support
| Platform | Behaviour |
|---|---|
| iOS 13+ | Native secure rendering — invisible on screenshot / recording / AirPlay / App Switcher. |
| Android | Falls back to a plain Text. Android has no per-view capture masking — protect the whole screen instead (see below). |
| Web, desktop | Falls back to a plain Text. |
See also: screen_protector
SecureText is intentionally narrow — it hides only the text it wraps, only
on iOS. For anything beyond that, pair it with
screen_protector:
- Android — this widget does nothing there, so use
screen_protectorto setFLAG_SECUREand block screenshots / recordings for the whole screen. - iOS, non-text content —
SecureTextcan only mask text drawn through its native secure canvas. To protect images, charts, custom-painted widgets, or an entire sensitive screen, usescreen_protectorto secure the whole app window (and blur/black it out in the App Switcher).
Rule of thumb: SecureText for a single line that must stay in the layout as
normal text; screen_protector for whole-screen or non-text protection and
for Android coverage. They compose cleanly — use both when you need
fine-grained iOS text masking and broad cross-platform coverage.
Limitations
- Transforms / opacity < 1 on
UiKitViewcan be lossy — keep the widget in a straightforward layout. - Font families must be already registered with iOS (bundled in the runner or shipped through Flutter's asset system). Unknown families fall back to the system font.
- If Apple ever renames or removes the private secure-canvas subview, the widget will keep rendering (via a fallback code path) but the screenshot masking will no longer apply. There is no way to detect that programmatically — pin the plugin version and test on new iOS majors.
Example
See example/ for a running app with buttons that mutate text/size/color
so you can verify live updates and take a screenshot to confirm the
SecureText line disappears while the regular Text stays visible.

