PostHog has extended session replay masking for Flutter apps with finer controls: text drawn through CustomPainter can now be masked by default, specific safe content can be explicitly unmasked while known-sensitive inputs stay hidden, and masking now covers the full height of text fields that grow as a user types. For a framework where a lot of UI — custom charts, branded input widgets, canvas-drawn text — doesn’t go through the standard widget tree, this closes a real gap: earlier masking rules built around standard Text and TextField widgets simply didn’t see anything rendered through a custom painter, which meant sensitive on-screen content could end up in a recording without anyone realising the default masking never applied to it.
Session replay is one of the few analytics capabilities where a config mistake doesn’t just produce bad data — it produces a compliance incident. A masking rule that silently fails to cover a custom-rendered balance field, PIN entry, or address form isn’t a chart that looks slightly off; it’s PII sitting in a session recording, potentially already synced to storage, before anyone notices the gap. Teams adopting Flutter’s newer masking controls need to actually verify coverage, not just assume that turning the feature on means everything sensitive is now hidden.
Data Points to Track
- Masking rule coverage per screen, mapped against every input field, custom-painted element, and dynamic-height text field on that screen
- Recording enablement state at the point a sensitive screen is entered, not just at session start
- Unmask exceptions, since content explicitly marked safe-to-show needs the same audit trail as content marked sensitive
- CustomPainter widget inventory across the app, cross-referenced against which of them currently fall under a masking rule
- SDK version per build, since masking behaviour has changed between releases and an app on an older SDK version may not have the coverage a newer changelog implies
- Recording opt-out / consent state, tracked alongside masking so you can distinguish “this session wasn’t recorded” from “this session was recorded but masked”
Setup Steps
- Inventory every screen with sensitive input (payment, auth, personal details) and check it against the current masking configuration before enabling replay broadly.
- Explicitly test CustomPainter-rendered text and dynamic-height fields, since these are exactly the cases the newer controls were built to fix — don’t assume an upgrade retroactively covers old recordings.
- Pin and track your PostHog Flutter SDK version in your release notes, so a masking regression can be traced to a specific dependency change.
- Add masking coverage checks to your QA pass for any new screen that includes custom-rendered or dynamically sized text.
- Set up an internal audit export of recorded sessions on sensitive screens on a recurring basis, to visually confirm masking is holding in production, not just in a test build.
Actionable Insights
Masking configuration is a fast-moving surface, not a set-and-forget toggle — every new custom widget or redesigned screen is a fresh opportunity for a gap. Treat masking coverage the way you’d treat test coverage: something you check per-screen, per-release, not something you assume holds because it held last quarter. The teams that avoid a real data incident here are the ones who audit actual recordings against actual screens on a schedule, rather than trusting the masking rule name to mean what it implies.
Related Resources
Need help tracking this in your app?
Our team sets up analytics pipelines for mobile and web teams every day. Talk to us and get your first events flowing in under an hour.
Talk to an expert