Overview
-- Session Replay provides privacy controls to ensure organizations of any - scale do not expose sensitive or personal data. Data is stored on - Datadog-managed cloud instances and encrypted at rest. -
-- Default privacy options for Session Replay protect end user privacy and - prevent sensitive organizational information from being collected. -
-- By enabling Mobile Session Replay, you can automatically mask sensitive - elements from being recorded through the RUM Mobile SDK. When data is - masked, that data is not collected in its original form by Datadog's SDKs - and thus is not sent to the backend. -
-Fine-grained masking
-- Using the masking modes below, you can override the default setup on a - per-application basis. Masking is fine-grained, which means you can override - masking for text and inputs, images, and touches individually to create a - custom configuration that suits your needs. -
-Text and input masking
-
- By default, the mask_all setting is enabled for all data. With
- this setting enabled, all text and input content on screen is masked, as
- shown below.
-
Mask sensitive inputs
-
- With the mask_sensitive_inputs setting enabled, all text and
- inputs are shown except those considered sensitive (passwords, emails, and
- phone numbers).
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setTextAndInputPrivacy(TextAndInputPrivacy.MASK_SENSITIVE_INPUTS)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: .maskSensitiveInputs,
- imagePrivacyLevel: imagePrivacyLevel,
- touchPrivacyLevel: touchPrivacyLevel
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- TextAndInputPrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.MASK_SENSITIVE_INPUTS,
-}
-
-SessionReplay.enable(config)
-
- final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.maskSensitiveInputs,
- replaySampleRate: replay,
- ),
-);
-
-
- Mask all inputs
-
- With the mask_all_inputs setting enabled, all inputs fields are
- masked in the replay.
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
-.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_ALL_INPUTS)
-.build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: .maskAllInputs,
- imagePrivacyLevel: imagePrivacyLevel,
- touchPrivacyLevel: touchPrivacyLevel
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- TextAndInputPrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.MASK_ALL_INPUTS,
-}
-
-SessionReplay.enable(config)
-
- final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.maskAllInputs,
- replaySampleRate: replay,
- ),
-);
-
-
- Mask all
-
- With the mask_all setting enabled, all text and input fields
- are masked in the replay.
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setTextAndInputPrivacy(TextAndInputPrivacy.MASK_ALL)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: .maskAll,
- imagePrivacyLevel: imagePrivacyLevel,
- touchPrivacyLevel: touchPrivacyLevel
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- TextAndInputPrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.MASK_ALL,
-}
-
-SessionReplay.enable(config)
-
- final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.maskAll,
- replaySampleRate: replay,
- ),
-);
-
-
- Image masking
-
- By default, the mask_all setting is enabled for all images.
- With this setting enabled, all images on screen are masked.
-
- For performance reasons, large images (those exceeding 1000x1000 total - pixels) are masked in Flutter, and will display "Large Image" in - the Session Replay player. -
-Mask all images
-
- With the mask_all setting enabled, all images are replaced by
- placeholders labeled 'Image' in the replay.
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setImagePrivacy(ImagePrivacy.MASK_ALL)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: textAndInputPrivacyLevel,
- imagePrivacyLevel: .maskAll,
- touchPrivacyLevel: touchPrivacyLevel
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- ImagePrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
-}
-
-SessionReplay.enable(config)
-
- final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- imagePrivacyLevel: ImagePrivacyLevel.maskAll,
- replaySampleRate: replay,
- ),
-);
-
-
- Mask content images
-- You can manage content masking while still allowing system or bundled images - to be visible. -
-
- Use the maskNonBundledOnly setting to replace non-bundled
- images with a "Content Image" placeholder in the replay.
-
-
-
- - In UIKit, the SDK can determine whether an image is bundled and can mask - it accordingly. - -
- - In SwiftUI, this determination isn't possible. Instead, the SDK uses a - heuristic: if an image exceeds 100×100 points, it is assumed to be - non-bundled and is masked. - -
- Select the mask_large_only setting, which replaces images
- with dimensions that exceed 100x100dp with a "Content Image"
- placeholder.
-
- Note: These dimensions refer to the drawable resource, - not the view's size. -
-application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setImagePrivacy(ImagePrivacy.MASK_LARGE_ONLY)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: textAndInputPrivacyLevel,
- imagePrivacyLevel: .maskNonBundledOnly,
- touchPrivacyLevel: touchPrivacyLevel
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- ImagePrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- imagePrivacyLevel: ImagePrivacyLevel.MASK_NON_BUNDLED_ONLY,
-}
-
-SessionReplay.enable(config)
-
-
- Bundled images are those that use AssetImage as their image
- provider.
-
final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- imagePrivacyLevel: ImagePrivacyLevel.maskNonAssetsOnly,
- replaySampleRate: replay,
- ),
-);
-
-
- Show all images
-
- With the mask_none setting enabled, all images are shown in the
- replay.
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setImagePrivacy(ImagePrivacy.MASK_NONE)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: textAndInputPrivacyLevel,
- imagePrivacyLevel: .maskNone,
- touchPrivacyLevel: touchPrivacyLevel
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- ImagePrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- imagePrivacyLevel: ImagePrivacyLevel.MASK_NONE,
-}
-
-SessionReplay.enable(config)
-
- Touch masking
-
- By default, the hide setting is enabled for all touches. With
- this setting enabled, all touches on screen are hidden.
-
Hide all touches
-
- With the hide setting enabled, all touches that occur during
- the replay are hidden. This is the default setting.
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setTouchPrivacy(TouchPrivacy.HIDE)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: textAndInputPrivacyLevel,
- imagePrivacyLevel: imagePrivacyLevel,
- touchPrivacyLevel: .hide
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- TouchPrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- touchPrivacyLevel: TouchPrivacyLevel.HIDE,
-}
-
-SessionReplay.enable(config)
-
- final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- imagePrivacyLevel: ImagePrivacyLevel.maskNone,
- replaySampleRate: replay,
- ),
-);
-
-
- Show all touches
-
- With the show setting enabled, all touches that occur during
- the replay are shown.
-
application.kt
-val sessionReplayConfig = SessionReplayConfiguration.Builder([sampleRate])
- .setTouchPrivacy(TouchPrivacy.SHOW)
- .build()
-SessionReplay.enable(sessionReplayConfig)
-
- AppDelegate.swift
-let sessionReplayConfig = SessionReplay.Configuration(
- replaySampleRate: sampleRate,
- textAndInputPrivacyLevel: textAndInputPrivacyLevel,
- imagePrivacyLevel: imagePrivacyLevel,
- touchPrivacyLevel: .show
-)
-SessionReplay.enable(with: sessionReplayConfig)
-
- App.tsx
-import {
- SessionReplay,
- SessionReplayConfiguration,
- TouchPrivacyLevel,
-} from "@datadog/mobile-react-native-session-replay";
-
-const config: SessionReplayConfiguration = {
- replaySampleRate: sampleRate,
- touchPrivacyLevel: TouchPrivacyLevel.SHOW,
-}
-
-SessionReplay.enable(config)
-
-
- Bundled images are those that use AssetImage as their image
- provider.
-
final configuration = DatadogConfiguration(
- // ...
-)..enableSessionReplay(
- DatadogSessionReplayConfiguration(
- touchPrivacyLevel: TouchPrivacyLevel.show,
- replaySampleRate: replay,
- ),
-);
-
-
- Privacy overrides
-- The sections above describe the global masking levels that apply to the - entire application. However, it is also possible to override these settings - at the view level. The same privacy levels as above are available for text - and inputs, images, touches, and an additional setting to completely hide a - specific view. -
-- To ensure overrides are recognized properly, they should be applied as early - as possible in the view lifecycle. This prevents scenarios where Session - Replay might process a view before applying the overrides. -
-- Privacy overrides affect views and their descendants. This means that even - if an override is applied to a view where it might have no immediate effect - (for example, applying an image override to a text input), the override - still applies to all child views. -
-- Overrides operate using a "nearest parent" principle: if a view - has an override, it uses that setting. Otherwise, it inherits the privacy - level from the closest parent in the hierarchy with an override. If no - parent has an override, the view defaults to the application's general - masking level. -
-Text and input override
-
- To override text and input privacy in Android classic view, use
- setSessionReplayTextAndInputPrivacy on a view instance and
- pass a value from the TextAndInputPrivacy enum. Passing
- null removes the override.
-
application.kt
-// Set a text and input override on your view
-myView.setSessionReplayTextAndInputPrivacy(TextAndInputPrivacy.MASK_SENSITIVE_INPUTS)
-// Remove a text and input override from your view
-myView.setSessionReplayTextAndInputPrivacy(null)
-
-
- To override text and input privacy in Jetpack Compose, use
- Modifier.sessionReplayTextAndInputPrivacy on the modifier
- of a composable and pass a value from the
- TextAndInputPrivacy enum.
-
application.kt
-// Set a text and input override on your view
-Text(modifier = Modifier
- .padding(16.dp)
- .sessionReplayTextAndInputPrivacy(textAndInputPrivacy = TextAndInputPrivacy.MASK_SENSITIVE_INPUTS),
- text = "Datadog"
-)
-
-
- To override text and input privacy in UIKit views, use
- dd.sessionReplayOverrides.textAndInputPrivacy on a view
- instance and set a value from the
- TextAndInputPrivacyLevel enum. Setting it to
- nil removes the override.
-
AppDelegate.swift
-// Set a text and input override on your view
-myView.dd.sessionReplayOverrides.textAndInputPrivacy = .maskSensitiveInputs
-// Remove a text and input override from your view
-myView.dd.sessionReplayOverrides.textAndInputPrivacy = nil
-
-
- To override text and input privacy in SwiftUI, wrap your content with
- SessionReplayPrivacyView and configure the
- textAndInputPrivacy parameter. You can combine this with
- other privacy settings in the same view for better performance.
-
ContentView.swift
-struct ContentView: View {
- @State private var username = ""
- @State private var password = ""
-
- var body: some View {
- // Set a text and input override on your SwiftUI content
- SessionReplayPrivacyView(textAndInputPrivacy: .maskAllInputs) {
- VStack {
- Text("User Profile")
- TextField("Enter name", text: $username)
- SecureField("Password", text: $password)
- }
- }
- }
-}
-
-
- To override text and input privacy in Flutter, use the
- SessionReplayPrivacy widget to override the privacy
- settings for an entire widget tree. Setting any value to
- null keeps the privacy values unchanged from values
- provided higher up the widget tree.
-
class MyWidget: StatelessWidget {
- Widget build() {
- return SessionReplayPrivacy(
- textAndInputPrivacyLevel: TextAndInputPrivacyLevel.maskAllInputs,
- child: TextField(
- decoration: InputDecoration(
- labelText: 'Simple Text Field',
- ),
- ),
- );
- }
-}
-
- Image override
-
- To override image privacy in Android classic view, use
- setSessionReplayImagePrivacy on a view instance and pass a
- value from the ImagePrivacy enum. Passing
- null removes the override.
-
application.kt
-// Set an image override on your view
-myView.setSessionReplayImagePrivacy(ImagePrivacy.MASK_ALL)
-// Remove an image override from your view
-myView.setSessionReplayImagePrivacy(null)
-
-
- To override image privacy in Jetpack Compose, use
- Modifier.sessionReplayImagePrivacy on the modifier of a
- composable and pass a value from the ImagePrivacy enum.
-
application.kt
-// Set a image privacy override on your image
-Image(modifier = Modifier
- .padding(16.dp)
- .sessionReplayImagePrivacy(imagePrivacy = ImagePrivacy.MASK_ALL),
- painter = painterResource(id = R.drawable.ic_datadog),
- contentDescription = null
-)
-
-
- To override image privacy in UIKit views, use
- dd.sessionReplayOverrides.imagePrivacy on a view instance
- and set a value from the ImagePrivacyLevel enum. Setting it
- to nil removes the override.
-
AppDelegate.swift
-// Set an image override on your view
-myView.dd.sessionReplayOverrides.imagePrivacy = .maskAll
-// Remove an image override from your view
-myView.dd.sessionReplayOverrides.imagePrivacy = nil
-
-
- To override image privacy in SwiftUI, wrap your content with
- SessionReplayPrivacyView and configure the
- imagePrivacy parameter.
-
ContentView.swift
-struct ProfileView: View {
- let profileImageURL = URL(string: "https://example.com/profile.jpg")
-
- var body: some View {
- // Set an image privacy override on your SwiftUI content
- SessionReplayPrivacyView(imagePrivacy: .maskAll) {
- VStack {
- Image("userAvatar")
- .resizable()
- .frame(width: 60, height: 60)
- .clipShape(Circle())
-
- AsyncImage(url: profileImageURL) { image in
- image.resizable()
- } placeholder: {
- ProgressView()
- }
- .frame(width: 100, height: 100)
- }
- }
- }
-}
-
-
- To override image privacy in Flutter, use the
- SessionReplayPrivacy widget to override the privacy
- settings for an entire widget tree. Setting any value to
- null keeps the privacy values unchanged from values
- provided higher up the widget tree.
-
class MyWidget: StatelessWidget {
- Widget build() {
- return SessionReplayPrivacy(
- imagePrivacyLevel: ImagePrivacyLevel.maskAll,
- child: Image.asset('assets/my_image.png'),
- );
- }
-}
-
- Touch override
-
- To override touch privacy in Android classic view, use
- setSessionReplayTouchPrivacy on a view instance and pass a
- value from the TouchPrivacy enum. Passing
- null removes the override.
-
application.kt
-// Set a touch override on your view
-view.setSessionReplayTouchPrivacy(TouchPrivacy.HIDE)
-// Remove a touch override from your view
-view.setSessionReplayTouchPrivacy(null)
-
-
- To override touch privacy in Jetpack Compose, use
- Modifier.sessionReplayTouchPrivacy on the modifier of a
- composable and pass a value from the TouchPrivacy enum.
-
application.kt
-// Set a touch privacy override on your view
-Column(modifier = Modifier
- .padding(16.dp)
- .sessionReplayTouchPrivacy(touchPrivacy = TouchPrivacy.HIDE)){
- // Content
-}
-
-
- To override touch privacy in UIKit views, use
- dd.sessionReplayOverrides.touchPrivacy on a view instance
- and set a value from the TouchPrivacyLevel enum. Setting it
- to nil removes the override.
-
AppDelegate.swift
-// Set a touch override on your view
-myView.dd.sessionReplayOverrides.touchPrivacy = .hide
-// Remove a touch override from your view
-myView.dd.sessionReplayOverrides.touchPrivacy = nil
-
-
- To override touch privacy in SwiftUI, wrap your content with
- SessionReplayPrivacyView and configure the
- touchPrivacy parameter.
-
ContentView.swift
-struct SettingsView: View {
- @State private var sliderValue = 0.5
-
- var body: some View {
- // Set a touch privacy override on your SwiftUI content
- SessionReplayPrivacyView(touchPrivacy: .hide) {
- VStack(spacing: 20) {
- Button("Some Action") {
- // Handle action
- }
- .padding()
- .background(Color.blue)
- .foregroundColor(.white)
- .cornerRadius(8)
-
- Slider(value: $sliderValue, in: 0...1) {
- Text("Some Value")
- }
- }
- .padding()
- }
- }
-}
-
-
- To override touch privacy in Flutter, use the
- SessionReplayPrivacy widget to override the privacy
- settings for an entire widget tree. Setting any value to
- null keeps the privacy values unchanged from values
- provided higher up the widget tree.
-
- Enabling touch privacy affects the entire widget tree, and cannot be - toggled back to "show" in children. -
-class MyWidget: StatelessWidget {
- Widget build() {
- return SessionReplayPrivacy(
- touchPrivacyLevel: TouchPrivacyLevel.hide,
- child: PinPadWidget(),
- );
- }
-}
-
- Hidden elements override
-
- For sensitive elements that need to be completely hidden, use the
- hidden setting.
-
- When an element is hidden, it is replaced by a placeholder
- labeled as "Hidden" in the replay, and its subviews are not
- recorded.
-
- Note: Marking a view as hidden does not
- prevent touch interactions from being recorded on that element. To hide
- touch interactions as well, use the
- touch override in addition to marking the
- element as hidden.
-
- Use setSessionReplayHidden(hide = true) to hide the
- element. Setting hide to false removes the
- override.
-
application.kt
-// Mark a view as hidden
-myView.setSessionReplayHidden(hide = true)
-// Remove the override from the view
-myView.setSessionReplayHidden(hide = false)
-
-
- Use Modifier.sessionReplayHide to hide the element in
- Jetpack Compose.
-
application.kt
-// Mark a Column as hidden
-Column(modifier = Modifier
- .padding(16.dp)
- .sessionReplayHide(hide = true)){
- // Content
-}
-
-
- In UIKit views, use dd.sessionReplayOverrides.hide to hide
- the element:
-
AppDelegate.swift
-// Mark a view as hidden
-myView.dd.sessionReplayOverrides.hide = true
-// Remove the override from the view
-myView.dd.sessionReplayOverrides.hide = false
-
-
- In SwiftUI, wrap your content with
- SessionReplayPrivacyView and set the
- hide parameter to true:
-
ContentView.swift
-struct PaymentView: View {
- @State private var cardNumber = ""
- @State private var cvv = ""
-
- var body: some View {
- // Mark SwiftUI content as hidden
- SessionReplayPrivacyView(hide: true) {
- VStack(spacing: 16) {
- Text("Payment Information")
- .font(.headline)
-
- TextField("Card Number", text: $cardNumber)
- .textFieldStyle(RoundedBorderTextFieldStyle())
-
- SecureField("CVV", text: $cvv)
- .textFieldStyle(RoundedBorderTextFieldStyle())
-
- Text("Card ending in 1234")
- .foregroundColor(.secondary)
- }
- .padding()
- }
- }
-}
-
-
- Note: Setting the hidden override to
- nil or false has the same effect—it disables
- the override.
-
- Combining privacy settings in SwiftUI -
-
- Combine multiple privacy settings in one
- SessionReplayPrivacyView for different configurations.
- Datadog recommends
- combining options in a single view rather than nesting multiple
- instances
- to avoid adding unnecessary view layers.
-
ContentView.swift
-struct UserProfileView: View {
- @State private var userBio = ""
- @State private var cardNumber = ""
-
- var body: some View {
- VStack(spacing: 30) {
- // Preferred: Combine multiple privacy settings in one view
- SessionReplayPrivacyView(
- textAndInputPrivacy: .maskSensitiveInputs,
- imagePrivacy: .maskNonBundledOnly,
- touchPrivacy: .show
- ) {
- VStack(spacing: 20) {
- // User profile section
- HStack {
- AsyncImage(url: URL(string: "https://example.com/profile.jpg")) { image in
- image.resizable()
- } placeholder: {
- Circle().fill(Color.gray.opacity(0.3))
- }
- .frame(width: 60, height: 60)
- .clipShape(Circle())
-
- VStack(alignment: .leading) {
- Text("John Doe")
- .font(.headline)
- TextField("Enter bio", text: $userBio)
- .textFieldStyle(RoundedBorderTextFieldStyle())
- }
- }
-
- Button("Save Profile") {
- // Save action
- print("Profile saved")
- }
- .padding()
- .background(Color.blue)
- .foregroundColor(.white)
- .cornerRadius(8)
- }
- .padding()
- }
-
- // For completely different privacy requirements, use separate `SessionReplayPrivacyView` instances
- SessionReplayPrivacyView(hide: true) {
- VStack(spacing: 16) {
- Text("Credit Card Information")
- .font(.headline)
- TextField("Card Number", text: $cardNumber)
- .textFieldStyle(RoundedBorderTextFieldStyle())
- }
- .padding()
- .background(Color.gray.opacity(0.1))
- .cornerRadius(8)
- }
- }
- .padding()
- }
-}
-
-
- Note: Each
- SessionReplayPrivacyView introduces an additional native
- view layer. For optimal performance, prefer combining privacy settings
- instead of nesting multiple privacy views when possible.
-
- To hide a widget tree in Flutter, use the
- SessionReplayPrivacy widget to override the privacy
- settings for an entire widget tree.
-
- Hiding a widget tree affects the entire widget tree, and cannot be
- toggled back to false in children, as Session Replay stops
- processing widget trees that are marked with hide.
-
class MyWidget: StatelessWidget {
- Widget build() {
- return SessionReplayPrivacy(
- hide: true,
- child: PinPadWidget(),
- );
- }
-}
-
-
- Privacy overrides are fully supported in React Native starting from
- version 2.8.0 of the Datadog
- React Native SDK. Although the underlying functionality is shared with native Android and
- iOS platforms, the integration in React Native is designed to align with
- common React patterns.
-
Behavior consistency
-- React Native's implementation is built on the same foundation as the - native Android and iOS SDKs. As a result, you can rely on the privacy - features behaving the same way across all three platforms. -
-Usage with SessionReplayView
-
- The SDK provides a set of React components under the
- SessionReplayView namespace, which are used to configure
- privacy settings within your React Native application.
-
To use them, import SessionReplayView as follows:
App.tsx
-import { SessionReplayView } from "@datadog/mobile-react-native-session-replay";
-
- This import provides access to four privacy-focused components.
-- Each of these components behaves like a regular React Native View, meaning - they can be used anywhere you would typically use a View, with the - addition of privacy-related behavior. -
-| Component | -Description | -Properties | -
|---|---|---|
SessionReplayView.Privacy |
- - Adds support for customizing text, image, and touch privacy settings - for its children. - | -
-
|
-
SessionReplayView.MaskAll |
-
- Applies the most restrictive privacy settings (MaskAll
- or platform equivalent) to all children.
- |
-
-
|
-
SessionReplayView.MaskNone |
-
- Applies the least restrictive settings (MaskNone or
- platform equivalent). All child components are visible.
- |
- (No additional properties) | -
SessionReplayView.Hide |
- Completely hides all child components from session replay. | -(No additional properties) | -
Integration approaches
-There are two ways to apply privacy overrides in React Native:
--
-
-
- Wrap specific components with a privacy-focused
-
SessionReplayViewto target only certain elements, or -
- -
- Replace an entire
<View>with a -SessionReplayViewto apply privacy settings to a whole - section of your UI. -
-
- This flexibility lets you control which parts of your app are masked or - visible in session replays. -
-
- Use SessionReplayView components to wrap specific parts
- of your UI where you want to override privacy settings.
-
For example, going from:
-App.tsx
-const App = () => {
- return (
- <View>
- {/* content */}
- <TextInput placeholder="First Name" value="Data" />
- <TextInput placeholder="Last Name" value="Dog" />
- {/* content */}
- </View>
- );
-}
-
- To:
-App.tsx
-const App = () => {
- return (
- <View>
- {/* content */}
- <SessionReplayView.MaskAll showTouch={true}>
- <TextInput placeholder="First Name" value="Data" />
- <TextInput placeholder="Last Name" value="Dog" />
- </SessionReplayView.MaskAll>
- {/* content */}
- </View>
- );
-}
-
-
- Replace an existing <View> with a
- SessionReplayView component directly. This is ideal
- when a view already encapsulates the section of the UI that needs
- modified privacy behavior.
-
For example, instead of:
-App.tsx
-const App = () => {
- return (
- <View>
- {/* content */}
- </View>
- );
-}
-
- You can use:
-App.tsx
-const App = () => {
- return (
- <SessionReplayView.MaskNone>
- {/* content */}
- </SessionReplayView.MaskNone>
- );
-}
-
- Combining privacy components
-
- You can freely combine the SessionReplayView components to
- apply different privacy settings to distinct sections of your UI. This is
- especially useful when you need a mix of hidden elements, masked input
- fields, and visible content within the same screen.
-
For example:
-App.tsx
-import { ImagePrivacyLevel, SessionReplayView, TextAndInputPrivacyLevel, TouchPrivacyLevel } from "@datadog/mobile-react-native-session-replay";
-
-const App = () => {
- return (
- <SessionReplayView.Privacy
- textAndInputPrivacy={TextAndInputPrivacyLevel.MASK_SENSITIVE_INPUTS}
- imagePrivacy={ImagePrivacyLevel.MASK_NONE}
- touchPrivacy={TouchPrivacyLevel.SHOW}>
- {/* content */}
- <SessionReplayView.MaskAll showTouch={true}>
- {/* content */}
- <SessionReplayView.MaskNone>
- {/* content */}
- </SessionReplayView.MaskNone>
- {/* content */}
- </SessionReplayView.MaskAll>
- {/* content */}
- <SessionReplayView.Hide>
- {/* content */}
- </SessionReplayView.Hide>
- </SessionReplayView.Privacy>
- );
-}
-
- Notes on WebViews
--
-
-
- Privacy overrides, aside from the
hiddenand -touchoptions, are not supported for WebViews. You can - primarily manage their privacy using the - browser SDK privacy settings. -
- -
- When a WebView is marked as
hidden, it is replaced by a - placeholder in the replay. However, the WebView itself continues to - collect and send data. To avoid this, it is recommended to use - browser SDK privacy settings - for managing WebView privacy, as they provide more targeted control. -
-
How and what data is masked
-- This section describes how the Datadog recorder handles masking based on - data type and how that data is defined. -
-Text masking strategies
-- Depending on how you've configured your privacy settings, the type of text, - and sensitivity of data, Datadog's masking rules apply different strategies - to different types of text fields. -
-| Text masking strategy | -Description | -Example | -
|---|---|---|
| No mask | -The text is revealed in the session replay | -
- "Hello world" →
- "Hello world"
- |
-
| Space-preserving mask | -- Each visible character is replaced with a lowercase "x" - | -
- "Hello world" →
- "xxxxx xxxxx"
- |
-
| Fixed-length mask | -- The entire text field is replaced with a constant of three asterisks - (***) - | -
- "Hello world" → "***"
- |
-
- With the above text strategies in mind, you have a few different options if
- you want to override the default privacy rule of mask in your
- configuration.
-
- The following chart shows how Datadog applies different text masking - strategies, using the rules you set up in your configuration, to the below - text types. -
-| Type | -Allow all | -Mask all | -Mask user input | -
|---|---|---|---|
| Sensitive text | -Fixed-length mask | -Fixed-length mask | -Fixed-length mask | -
| Input and option text | -No mask | -Fixed-length mask | -Fixed-length mask | -
| Static text | -No mask | -Space-preserving mask | -No mask | -
| Hint text | -No mask | -Fixed-length mask | -No mask | -
Text masking definitions
-- Find below a description of how Datadog's recorder treats each text type. -
-Sensitive text
-- Sensitive text includes passwords, e-mails, and phone numbers marked in a - platform-specific way, and other forms of sensitivity in text available to - each platform. -
-Sensitive text can be detected in:
--
-
- Edit Text -
- Address information -
Sensitive text can be detected in:
--
-
- Text Field -
- Text View -
- Address information -
- Credit card numbers -
- One-time codes -
Sensitive text can be detected in the following components.
-| Component | -Platform(s) | -
|---|---|
| Text Field | -iOS | -
| Text View | -iOS | -
| Edit Text | -Android | -
| Address information | -iOS, Android | -
| Credit card numbers | -iOS | -
| One-time codes | -iOS | -
TextInputType.name |
- TextInputType.phone |
- TextInputType.emailAddress |
- TextInputType.streetAddress |
- TextInputType.twitter |
- TextInputType.visiblePassword |
-
Input and option text
-- Input and option text is text entered by the user with a keyboard or other - text-input device, or a custom (non-generic) value in selection elements. -
-This includes the below.
--
-
-
- User-entered text in:
-
-
-
- Text Field -
- Text View -
- -
- User-selected options in:
-
-
-
- Value Picker -
- Segment -
- -
- Notable exclusions:
-
-
-
- - Placeholder (hint) texts in Text Field and Text View (not entered by - the user) - -
- Non-editable texts in Text View -
- Month, day, and year labels in Date Picker (generic values) -
-
-
-
-
- User-entered text in:
-
-
-
- Edit Text -
- -
- User-selected options in:
-
-
-
- Value Picker -
- Drop Down List -
- -
- Notable exclusions:
-
-
-
- - Placeholder (hint) texts in Edit Text (not entered by the user) - -
- Month, day, and year labels in Date Picker (generic values) -
-
-
-
-
- User-entered text in:
-
-
-
- Text Field (iOS) -
- Text View (iOS) -
- Edit Text (Android) -
- -
- User-selected options in:
-
-
-
- Value Picker (iOS + Android) -
- Segment (iOS) -
- Drop Down List (Android) -
- -
- Notable exclusions:
-
-
-
- - Placeholder (hint) texts in Text Field, Text View and Edit Text (not - entered by the user) - -
- Non-editable texts in Text View (iOS). -
- Month, day, and year labels in Date Picker (generic values) -
-
-
-
-
- User-entered text in EditableText, which is used in:
-
-
-
- TextField -
- CupertinoTextField -
- many custom TextField implementations -
- -
- Notable exclusions:
-
-
-
- - Placeholder (hint) texts in Text Field and Text View (not entered by - the user) - -
- Text in Text Decorations (not entered by the user) -
- Month, day, and year labels in Date Picker (generic values) -
-
Static text
-- Static text is any text that is not directly entered by the user. This - includes the below. -
-All texts in:
--
-
- Texts in non-editable Text View -
- Month, day, and year labels in the date and time picker -
- - Values updated in response to gesture interaction with input elements, - such as the current value of the Slider - -
- - Other controls, not considered as "user input elements", such - as Labels, Tab Bar, and Navigation Bar - -
-
-
- Checkbox and Radio Button titles -
- Month, day, and year labels in the date and time picker -
- - Values updated in response to gesture interaction with input elements, - such as the current value of the Slider - -
- - Other controls, not considered as "user input elements", such - as Tabs - -
-
-
- Checkbox and Radio Button titles (Android) -
- Texts in non-editable Text View (iOS) -
- Month, day and year labels in the date and time picker -
- - Values updated in response to gesture interaction with input elements, - such as the current value of the Slider - -
- - Other controls, not considered as "user input elements", such - as Labels, Tab Bar, and Navigation Bar (iOS), or Tabs (Android) - -
-
-
- Checkbox and Radio Button titles -
- Month, day and year labels in the date and time picker -
- - Values updated in response to gesture interaction with input elements, - such as the current value of the Slider - -
- - Other controls, not considered as "user input elements", such - as Text, Tab Bar, and Bottom Navigation Bar - -
Hint text
-- Hint text is static text in editable text elements or option selectors that - is displayed when no value is given. This includes: -
--
-
- Placeholders in Text Field -
- Placeholders in Text View -
-
-
- Hints in Edit Text -
- Prompts in Drop Down lists -
-
-
- Placeholders in Text Field (iOS), Text View (iOS) -
- Hints in Edit Text (Android) -
- Prompts in Drop Down lists (Android) -
-
-
- InputDecoration elements in TextView -
- Placeholder text in CupertinoTextField -
Appearance masking
-- The following chart shows how we apply different appearance masking - strategies, using the rules you set up in your configuration, to the below - text types. -
-| Type | -Allow all | -Mask all | -Mask user input | -
|---|---|---|---|
| Revealing attributes | -- | - | - |
| Other attributes | -- | - | - |
Revealing attributes
-- Revealing attributes are attributes that can reveal or suggest the value of - input elements and can be used to infer a user's input or selection. -
-This includes:
-Shapes
--
-
- Background of selected option in Segment -
- Circle surrounding the selected date in a Date Picker -
- Thumb of a Slider -
Text attributes
--
-
- The color of a label rendering the selected date in Date Picker -
- The position of the first and last option in Value Picker -
Shapes
--
-
- Selection mark in Checkbox -
- Thumb of a Slider -
Text attributes
--
-
- The position of the first and last option in Value Picker -
Shapes
-| Type | -Platform(s) | -
|---|---|
| Background of selected option in Segment | -iOS | -
| Circle surrounding the selected date in Date Picker | -iOS | -
| Selection mark in Checkbox | -Android | -
| Thumb of a Slider | -iOS, Android | -
Text attributes
-| Type | -Platform(s) | -
|---|---|
| - The color of a label rendering the selected date in Date Picker - | -iOS | -
| The position of the first and last option in Value Picker | -iOS, Android | -
Shapes
--
-
- Background of selected option in Segment -
- Circle surrounding the selected date in a Date Picker -
- Thumb of a Slider -
Text attributes
--
-
- The color of a label rendering the selected date in Date Picker -
- The position of the first and last option in Value Picker -
Touch interactions
-- The following chart shows how we apply different touch interaction - strategies, using the rules you set up in your configuration, to the below - text types. While any interaction that happens on an on-screen keyboard is - masked, interactions with other elements are not masked. -
-| Type | -Allow all | -Mask all | -Mask user input | -
|---|---|---|---|
| Other attributes | -- | - | - |
| On-screen keyboard | -- | - | - |
Image masking
-- The following chart shows how we apply different image masking strategies: -
-| Type | -Mask None | -
- Mask Large Only
-
- Mask Non Bundled Only
-
-
- Mark Large Only (Android) / Mask Non Bundled Only (iOS)
-
- |
- Mask All | -
|---|---|---|---|
| Content Image | -Shown | -Masked | -Masked | -
| System Image | -Shown | -Shown | -Masked | -

