Skip to content

Commit 69c28a9

Browse files
romtsnlizokm
andauthored
feat(android): Add custom masking options for session replay (#11624)
* feat(android): Add custom masking options for session replay * feat(android): Add custom masking options for session replay * Add missing imports * Rearrange folders * Add required version * Add masking example images * Update docs/platforms/android/session-replay/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Fix formatting * Fix and add masking behavior section * Add missing images * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock <[email protected]> * Update docs/platforms/android/session-replay/privacy/index.mdx * Add old way of disabling redaction --------- Co-authored-by: Liza Mock <[email protected]>
1 parent cd56ad6 commit 69c28a9

File tree

4 files changed

+169
-7
lines changed

4 files changed

+169
-7
lines changed

docs/platforms/android/session-replay/index.mdx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,23 @@ Sampling begins as soon as a session starts. `sessionSampleRate` is evaluated fi
9494

9595
## Privacy
9696

97-
The SDK is recording and aggressively redacting all text and images. We plan to add fine controls for redacting, but in this version, we just allow either on or off. The default is on. Please don’t turn it off if you have sensitive data in your app. Before the Beta is complete, we'll give you the controls you need.
97+
The SDK is recording and aggressively masking all text, images and webviews. Please don’t turn it off if you have sensitive data in your app.
98+
However, if you're working on a mobile app that's free of PII or other types of private data, you can opt out of the default text and image masking settings. To learn more about Session Replay privacy, [read our docs](/platforms/android/session-replay/privacy/).
9899

99100
<Note>
100101

101-
Jetpack Compose views are not yet redacted. This is being [tracked here](https://github.com/getsentry/sentry-java/issues/3577).
102-
If you encounter any other data not being redacted with the default settings, please let us know through a [GitHub issue](https://github.com/getsentry/sentry-java/issues/new?assignees=&labels=Platform%3A+Android%2CType%3A+Bug&projects=&template=bug_report_android.yml).
102+
If you find that any other data isn't being masked with the default settings, please let us know by creating a [GitHub issue](https://github.com/getsentry/sentry-java/issues/new?assignees=&labels=Platform%3A+Android%2CType%3A+Bug&projects=&template=bug_report_android.yml).
103103

104104
</Note>
105105

106-
To disable redaction altogether (not to be used on applications with sensitive data):
106+
To disable masking altogether (not to be used on applications with sensitive data):
107107

108108
```kotlin
109-
options.experimental.sessionReplay.redactAllText = false
110-
options.experimental.sessionReplay.redactAllImages = false
109+
options.experimental.sessionReplay.maskAllText = false
110+
options.experimental.sessionReplay.maskAllImages = false
111+
// if you're on version < 7.15.0
112+
// options.experimental.sessionReplay.redactAllText = false
113+
// options.experimental.sessionReplay.redactAllImages = false
111114
```
112115

113116
## Error Linking
@@ -120,8 +123,12 @@ Errors that happen on the page while a replay is running will be linked to the r
120123

121124
## FAQ
122125

126+
Q: Why are parts of my replay not masked?
127+
A: Text fields, input fields, images, video players and webviews are all masked by default. Local assets, such as colors or vector drawables, aren't masked because the likelihood of these assets containing PII is low. If you encounter a view/component that should be masked by default, consider opening a [GitHub issue](https://github.com/getsentry/sentry-java/issues).
128+
123129
Q: Does Session Replay work with Jetpack Compose?
124-
A: Yes, but we're still adding support for redaction for Jetpack Compose views. Redaction will be added during the Beta program and after GA these views will be masked by default.
130+
A: Yes, by default, text, input field, and image composables should be masked. Masking within embedded Android views (`AndroidView`)
131+
in Compose isn't currently supported. If you encounter composables that aren't masked but should be, consider opening a [GitHub issue](https://github.com/getsentry/sentry-java/issues).
125132

126133
Q: What's the lowest version of Android supported?
127134
A: Recording only happens on Android 8 (API level 26) or newer. For devices running an older version, SDK features other than recording work normally.
22.3 KB
Loading
41.8 KB
Loading
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
---
2+
title: Privacy
3+
sidebar_order: 5501
4+
notSupported:
5+
description: "Learn how to mask parts of your app's data in Session Replay."
6+
---
7+
8+
<Alert>
9+
10+
Using custom masking in your Session Replays may accidentally expose sensitive customer data. Before publishing an App with Session Replay enabled, make sure to test it thoroughly to ensure that no sensitive data is exposed.
11+
12+
13+
</Alert>
14+
15+
By default, our Session Replay SDK masks all text content, images, webviews, and user input. This helps ensure that no sensitive data is exposed. You can also manually choose which parts of your app's data you want to mask by using the different options listed below.
16+
17+
To disable the default masking behavior (not to be used on applications with sensitive data):
18+
19+
```kotlin
20+
options.experimental.sessionReplay.maskAllText = false
21+
options.experimental.sessionReplay.maskAllImages = false
22+
// if you're on version < 7.15.0
23+
// options.experimental.sessionReplay.redactAllText = false
24+
// options.experimental.sessionReplay.redactAllImages = false
25+
```
26+
27+
|Session Replay Unmasked | Session Replay Masked |
28+
|:-----------------------------:|:---------------------------------------: |
29+
|![session replay unmasked](./img/session-replay.jpg) |![session replay masked](./img/session-replay-redacted.jpg) |
30+
31+
32+
_Make sure your Sentry Android SDK version is at least 7.15.0._
33+
34+
## Mask by View Class
35+
36+
You can choose which type of view you want to mask or unmask by using the `addMaskViewClass` or `addUnmaskViewClass` options.
37+
38+
Let's say you have:
39+
- A custom view that you want to mask
40+
- A `TextView` subclass (which normally would be masked) that you don't want to mask
41+
42+
You can set the options like this:
43+
44+
```kotlin
45+
options.experimental.sessionReplay.addMaskViewClass("com.example.MyCustomView")
46+
options.experimental.sessionReplay.addUnmaskViewClass("com.example.MyCustomTextView")
47+
```
48+
49+
<Note>
50+
51+
If you're using a code obfuscation tool (R8/ProGuard), adjust your proguard rules accordingly so your custom view class names don't get minified.
52+
53+
</Note>
54+
55+
### Class Hierarchy
56+
57+
The masking behavior applies to classes and their subclasses. This means if you add a view via `addMaskViewClass` (for example, `TextView`, which is the default behavior), its respective subclasses (`RadioButton`, `CheckBox`, `EditText`, and so on) will also be masked. For example, you can do the following:
58+
59+
```kotlin
60+
options.experimental.sessionReplay.addMaskViewClass("android.widget.TextView") // mask TextView and all its subclasses
61+
options.experimental.sessionReplay.addUnmaskViewClass("android.widget.RadioButton") // but unmask RadioButton and all its subclasses
62+
```
63+
64+
## Mask by View Instance
65+
66+
You can also choose to mask or unmask a specific view instance by using tags like this:
67+
68+
```xml
69+
<View
70+
android:id="@+id/my_view"
71+
android:layout_width="wrap_content"
72+
android:layout_height="wrap_content"
73+
android:tag="sentry-mask|sentry-unmask"
74+
/>
75+
```
76+
77+
```kotlin
78+
view.tag = "sentry-mask|sentry-unmask"
79+
```
80+
81+
If your view already has a tag assigned, you can set the masking tag by a sentry-specific id:
82+
83+
```xml
84+
<View
85+
android:id="@+id/my_view"
86+
android:layout_width="wrap_content"
87+
android:layout_height="wrap_content">
88+
89+
<tag android:id="@id/sentry_privacy" android:value="mask|unmask"/>
90+
</View>
91+
```
92+
93+
```kotlin
94+
view.setTag(io.sentry.android.replay.R.id.sentry_privacy, "mask|unmask")
95+
```
96+
97+
We also provide convenient extension functions for Kotlin:
98+
99+
```kotlin
100+
view.sentryReplayMask()
101+
// or
102+
view.sentryReplayUnmask()
103+
```
104+
105+
## Jetpack Compose
106+
107+
We only support masking specific composables in Jetpack Compose. Since composables are functions, not classes, masking by view class isn't possible.
108+
109+
In the example below, we want the "Hello" message to be captured in the replay, but not the custom composable. (By default, all text composables are masked.)
110+
111+
```kotlin
112+
import io.sentry.android.replay.sentryReplayMask
113+
import io.sentry.android.replay.sentryReplayUnmask
114+
115+
Column(
116+
verticalArrangement = Arrangement.Center,
117+
horizontalAlignment = Alignment.CenterHorizontally,
118+
modifier = Modifier.fillMaxSize()
119+
) {
120+
MyCustomComposable(
121+
modifier = Modifier.fillMaxWidth().sentryReplayMask()
122+
...
123+
)
124+
Text("Hello", modifier = Modifier.sentryReplayUnmask())
125+
}
126+
```
127+
128+
Currently, we don't support masking anything within embedded Android views (`AndroidView`), but you can still mask the entire view as follows:
129+
130+
```kotlin
131+
import io.sentry.android.replay.sentryReplayMask
132+
133+
AndroidView(
134+
modifier = Modifier.sentryReplayMask(),
135+
factory = { context -> ... }
136+
)
137+
```
138+
139+
## General Masking Rules
140+
141+
142+
### View Groups
143+
144+
- If a `ViewGroup` is marked as masked, **all its child views will also be masked**, even if some views would normally not be masked. This prioritizes safety and ensures no sensitive information is unintentionally exposed.
145+
146+
- If a `ViewGroup` is marked as unmasked, **its child views don't automatically inherit this behavior**. You'll need to explicitly mark each child view as unmasked if you want them to appear in the replay.
147+
148+
### Masking Priority
149+
150+
Masking and unmasking rules are applied in the following order:
151+
152+
1. Check if a view is marked as `unmasked` via a tag/extension or function/modifier.
153+
2. Check if a view is marked as `masked` via a tag/extension or function/modifier.
154+
3. Check if a view's class is marked as unmasked via `addUnmaskViewClass`.
155+
4. Check if a view's class is marked as masked via `addMaskViewClass`.

0 commit comments

Comments
 (0)