-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
Showing
4 changed files
with
169 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+22.3 KB
docs/platforms/android/session-replay/privacy/img/session-replay-redacted.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
155 changes: 155 additions & 0 deletions
155
docs/platforms/android/session-replay/privacy/index.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
--- | ||
title: Privacy | ||
sidebar_order: 5501 | ||
notSupported: | ||
description: "Learn how to mask parts of your app's data in Session Replay." | ||
--- | ||
|
||
<Alert> | ||
|
||
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. | ||
|
||
|
||
</Alert> | ||
|
||
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. | ||
|
||
To disable the default masking behavior (not to be used on applications with sensitive data): | ||
|
||
```kotlin | ||
options.experimental.sessionReplay.maskAllText = false | ||
options.experimental.sessionReplay.maskAllImages = false | ||
// if you're on version < 7.15.0 | ||
// options.experimental.sessionReplay.redactAllText = false | ||
// options.experimental.sessionReplay.redactAllImages = false | ||
``` | ||
|
||
|Session Replay Unmasked | Session Replay Masked | | ||
|:-----------------------------:|:---------------------------------------: | | ||
|![session replay unmasked](./img/session-replay.jpg) |![session replay masked](./img/session-replay-redacted.jpg) | | ||
|
||
|
||
_Make sure your Sentry Android SDK version is at least 7.15.0._ | ||
|
||
## Mask by View Class | ||
|
||
You can choose which type of view you want to mask or unmask by using the `addMaskViewClass` or `addUnmaskViewClass` options. | ||
|
||
Let's say you have: | ||
- A custom view that you want to mask | ||
- A `TextView` subclass (which normally would be masked) that you don't want to mask | ||
|
||
You can set the options like this: | ||
|
||
```kotlin | ||
options.experimental.sessionReplay.addMaskViewClass("com.example.MyCustomView") | ||
options.experimental.sessionReplay.addUnmaskViewClass("com.example.MyCustomTextView") | ||
``` | ||
|
||
<Note> | ||
|
||
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. | ||
|
||
</Note> | ||
|
||
### Class Hierarchy | ||
|
||
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: | ||
|
||
```kotlin | ||
options.experimental.sessionReplay.addMaskViewClass("android.widget.TextView") // mask TextView and all its subclasses | ||
options.experimental.sessionReplay.addUnmaskViewClass("android.widget.RadioButton") // but unmask RadioButton and all its subclasses | ||
``` | ||
|
||
## Mask by View Instance | ||
|
||
You can also choose to mask or unmask a specific view instance by using tags like this: | ||
|
||
```xml | ||
<View | ||
android:id="@+id/my_view" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:tag="sentry-mask|sentry-unmask" | ||
/> | ||
``` | ||
|
||
```kotlin | ||
view.tag = "sentry-mask|sentry-unmask" | ||
``` | ||
|
||
If your view already has a tag assigned, you can set the masking tag by a sentry-specific id: | ||
|
||
```xml | ||
<View | ||
android:id="@+id/my_view" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content"> | ||
|
||
<tag android:id="@id/sentry_privacy" android:value="mask|unmask"/> | ||
</View> | ||
``` | ||
|
||
```kotlin | ||
view.setTag(io.sentry.android.replay.R.id.sentry_privacy, "mask|unmask") | ||
``` | ||
|
||
We also provide convenient extension functions for Kotlin: | ||
|
||
```kotlin | ||
view.sentryReplayMask() | ||
// or | ||
view.sentryReplayUnmask() | ||
``` | ||
|
||
## Jetpack Compose | ||
|
||
We only support masking specific composables in Jetpack Compose. Since composables are functions, not classes, masking by view class isn't possible. | ||
|
||
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.) | ||
|
||
```kotlin | ||
import io.sentry.android.replay.sentryReplayMask | ||
import io.sentry.android.replay.sentryReplayUnmask | ||
|
||
Column( | ||
verticalArrangement = Arrangement.Center, | ||
horizontalAlignment = Alignment.CenterHorizontally, | ||
modifier = Modifier.fillMaxSize() | ||
) { | ||
MyCustomComposable( | ||
modifier = Modifier.fillMaxWidth().sentryReplayMask() | ||
... | ||
) | ||
Text("Hello", modifier = Modifier.sentryReplayUnmask()) | ||
} | ||
``` | ||
|
||
Currently, we don't support masking anything within embedded Android views (`AndroidView`), but you can still mask the entire view as follows: | ||
|
||
```kotlin | ||
import io.sentry.android.replay.sentryReplayMask | ||
|
||
AndroidView( | ||
modifier = Modifier.sentryReplayMask(), | ||
factory = { context -> ... } | ||
) | ||
``` | ||
|
||
## General Masking Rules | ||
|
||
|
||
### View Groups | ||
|
||
- 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. | ||
|
||
- 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. | ||
|
||
### Masking Priority | ||
|
||
Masking and unmasking rules are applied in the following order: | ||
|
||
1. Check if a view is marked as `unmasked` via a tag/extension or function/modifier. | ||
2. Check if a view is marked as `masked` via a tag/extension or function/modifier. | ||
3. Check if a view's class is marked as unmasked via `addUnmaskViewClass`. | ||
4. Check if a view's class is marked as masked via `addMaskViewClass`. |