Privacy controls
Contents
PostHog offers a range of controls to limit what data is captured by session recordings. Our privacy controls run in the browser or mobile app. So, masked data is never sent over the network to PostHog.
Input elements
As any input element is highly likely to contain sensitive text such as email or password, we mask these by default. You can explicitly set this to false to disable the masking. You can then specify inputs types you would like to be masked.
Mask or un-mask specific inputs
You can control the masking more granularly by using maskInputFn to customize how the masking behaves. For example, you may want to only redact text that looks like an email address, or comes from inputs that aren't search boxes.
Text elements
General text is not masked by default, but we provide multiple options for masking text:
Mask all text
IMPORTANT: The
textrelated config options only apply to non-input text. Inputs are masked differently and have separate methods (as detailed above).
Mask or un-mask specific text
You can use a CSS selector to mask specific elements. For example, you may want to mask all elements with the class email or the ID sensitive.
IMPORTANT: The masking of an element applies to its children meaning
:notselectors do not work. The ability to selectively mask elements is detailed below
You can further control the text that gets masked. For example, by only masking text that looks like an email
Other Elements
If your application displays sensitive user information outside of input or text fields, or if there are areas of your application that you simply don't want to capture, you need to update your codebase to prevent PostHog from capturing this information during session recordings.
To do so, you should add the CSS class name ph-no-capture to elements which should not be recorded. This will lead to the element being replaced with a block of the same size when you play back the recordings. Make sure everyone who watches recordings in your team is aware of this, so that they don't think your product is broken when something doesn't show up!
Note that adding ph-no-capture will also prevent any autocapture events from being captured from that element.
Common example configs
Maximum privacy - mask everything
Limited privacy - try to mask all email / password related things
You can mask content that looks like it contains an email or password.
For passwords, it is important to note that "click to show password" buttons typically turn the input type to text. This would then reveal the password. Thus instead of checking for type='password', you need to check a different field, like id:
Selective privacy - only reveal things that are marked as safe
Instead of selectively masking, we can selectively unmask fields that you are sure are safe.
This assumes you are adding a data attribute to every "safe" element like <p data-record="true">I will be visible!</p>
To replace any type of View with a redacted version in the recording, set the tag to ph-no-capture.
Masking in Jetpack Compose
- You can manually mark a Compose View for masking using the
postHogMask()view modifier:
Handling sensitive third-party screens
Third-party components (like payment forms or authentication screens) are often rendered in separate view hierarchies that can't be accessed or modified for masking.
For these cases, manually controlling the recording state is the only reliable solution. For example:
To replace any type of UIView with a redacted version in the replay, set the accessibilityIdentifier to ph-no-capture:
Note: For SwiftUI please refer to the Masking in SwiftUI section below
Masking in SwiftUI
When using the SwiftUI TextField with UITextInputTraits, setting traits such as
TextField("Email", text: ...).keyboardType(.emailAddress)will always be automatically masked since it's for private text.The SwiftUI SecureField view is always automatically masked.
You can manually mark a SwiftUI View for masking using the
postHogMask()view modifier:SwiftThe
postHogNoMask()view modifier can be used to prevent a view from being masked in session recordings, regardless of any default masking behavior:Swift
Apps built with Xcode 26 use a new SwiftUI rendering model that changes how SwiftUI views map to UIKit. This can cause postHogMask() and postHogNoMask() to behave inconsistently on primitive views like Text, Image, and Button.
If you're building with Xcode 26, update to version 3.36.2 or later to ensure these modifiers work correctly.
Handling sensitive third-party screens
Third-party components (like payment forms or authentication screens) are often rendered in separate view hierarchies that can't be accessed or modified for masking.
For these cases, manually controlling the recording state is the only reliable solution. For example:
Masking
By default all text, inputs, and images are masked.
Password inputs are always masked no matter your config.
You can configure masking levels when you initialise PostHog
Manual Masking
To replace any type of React.Component with a redacted version in the replay, set the accessibilityLabel to ph-no-capture:
Masking All Texts and Images
Masking in Flutter
- You can manually mark a Widget for masking using the
PostHogMaskWidgetWidget:
Network capture
Session replay also allows you to capture network requests and responses. Headers and bodies can include sensitive information. We scrub some headers automatically, but if your network requests and responses include sensitive information you can provide a function to scrub them. Read more in our network capture docs