From 649b485014565c510be062dec2ec8cda239b8824 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 21 Oct 2024 13:42:34 +0200 Subject: [PATCH 01/27] feat(android): Add custom masking options for session replay --- .../platforms/android/session-replay/index.mdx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/platforms/android/session-replay/index.mdx b/docs/platforms/android/session-replay/index.mdx index 959394fdb63d2..e7f2091a6dacf 100644 --- a/docs/platforms/android/session-replay/index.mdx +++ b/docs/platforms/android/session-replay/index.mdx @@ -94,20 +94,20 @@ Sampling begins as soon as a session starts. `sessionSampleRate` is evaluated fi ## Privacy -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. +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. +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/). -Jetpack Compose views are not yet redacted. This is being [tracked here](https://github.com/getsentry/sentry-java/issues/3577). -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). +If you encounter any other data not being masked 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). -To disable redaction altogether (not to be used on applications with sensitive data): +To disable masking altogether (not to be used on applications with sensitive data): ```kotlin -options.experimental.sessionReplay.redactAllText = false -options.experimental.sessionReplay.redactAllImages = false +options.experimental.sessionReplay.maskAllText = false +options.experimental.sessionReplay.maskAllImages = false ``` ## Error Linking @@ -120,8 +120,12 @@ Errors that happen on the page while a replay is running will be linked to the r ## FAQ +Q: Why are parts of my replay not masked? +A: Text fields, input fields, images, video players and webviews are all masked by default. Local assets, such as colors or vector drawables, are not masked due to their low likelihood of containing PII. If you encounter a view/component that should be masked by default, consider opening a [GitHub issue](https://github.com/getsentry/sentry-java/issues). + Q: Does Session Replay work with Jetpack Compose? -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. +A: Yes, by default text, input field and image composables should be masked. Masking within embedded android views (`AndroidView`) +in Compose is currently not supported. If you encounter composables that are not masked but should be, consider opening a [GitHub issue](https://github.com/getsentry/sentry-java/issues). Q: What's the lowest version of Android supported? 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. From 877f5d4875a32c60d36b05363af7965f0766f967 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 21 Oct 2024 13:43:49 +0200 Subject: [PATCH 02/27] feat(android): Add custom masking options for session replay --- .../android/session-replay/privacy.mdx | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 docs/platforms/android/session-replay/privacy.mdx diff --git a/docs/platforms/android/session-replay/privacy.mdx b/docs/platforms/android/session-replay/privacy.mdx new file mode 100644 index 0000000000000..08f5583422752 --- /dev/null +++ b/docs/platforms/android/session-replay/privacy.mdx @@ -0,0 +1,124 @@ +--- +title: Privacy +sidebar_order: 5501 +notSupported: +description: "Learn how to mask parts of your app's data in Session Replay." +--- + + + +Before publising an App with Session Replay enabled, make sure to test it thoroughly to ensure that no sensitive data is exposed. + +If you choose to use custom masking in your Session Replays, you may accidentally expose sensitive customer data. Be sure to double-check what you choose to expose. + + + +By default, our Session Replay SDK masks all text content, images, webviews and user input. This helps ensure that no sensitive data will be 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 +``` + +## 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") +``` + + + +If you're using a code obfuscation tool (R8/ProGuard), adjust your proguard rules accordingly so your custom view class names are not minified. + + + +### 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`, etc.) 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 + +``` + +```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 + + + +``` + +```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 don't have a concept of classes (they are all composable functions), masking by view class is not supported. + +In this example, we want the "Hello" message to be captured in the replay (by default, all text composables are masked), but not the custom composable: + +```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.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 +AndroidView( + modifier = Modifier.sentryReplayMask(), + factory = { context -> ... } +) +``` From 5f739563cd0daf33a7cf6791fb956273c2b34aac Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 21 Oct 2024 13:56:42 +0200 Subject: [PATCH 03/27] Add missing imports --- docs/platforms/android/session-replay/privacy.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy.mdx b/docs/platforms/android/session-replay/privacy.mdx index 08f5583422752..d2234ed494620 100644 --- a/docs/platforms/android/session-replay/privacy.mdx +++ b/docs/platforms/android/session-replay/privacy.mdx @@ -107,7 +107,7 @@ Column( modifier = Modifier.fillMaxSize() ) { MyCustomComposable( - modifier = Modifier.sentryReplayMask() + modifier = Modifier.fillMaxWidth().sentryReplayMask() ... ) Text("Hello", modifier = Modifier.sentryReplayUnmask()) @@ -117,6 +117,8 @@ Column( 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 -> ... } From 82d92b7186978b1489fd9b39ad23a31545c36d50 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 21 Oct 2024 14:07:09 +0200 Subject: [PATCH 04/27] Rearrange folders --- .../android/session-replay/{privacy.mdx => privacy/index.mdx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/platforms/android/session-replay/{privacy.mdx => privacy/index.mdx} (100%) diff --git a/docs/platforms/android/session-replay/privacy.mdx b/docs/platforms/android/session-replay/privacy/index.mdx similarity index 100% rename from docs/platforms/android/session-replay/privacy.mdx rename to docs/platforms/android/session-replay/privacy/index.mdx From 0a7bab98fa3c9d2b3d58284857586cf90da5200a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 21 Oct 2024 14:09:04 +0200 Subject: [PATCH 05/27] Add required version --- docs/platforms/android/session-replay/privacy/index.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index d2234ed494620..1ad0b16747ce5 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -22,6 +22,8 @@ options.experimental.sessionReplay.maskAllText = false options.experimental.sessionReplay.maskAllImages = false ``` +_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. From fca534d7ac7e23365f49d50337631f0baaa44c42 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 21 Oct 2024 18:22:27 +0200 Subject: [PATCH 06/27] Add masking example images --- docs/platforms/android/session-replay/privacy/index.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 1ad0b16747ce5..49591f8039d08 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -22,6 +22,8 @@ options.experimental.sessionReplay.maskAllText = false options.experimental.sessionReplay.maskAllImages = false ``` +![Session Replay unredacted](./img/session-replay.jpg) ![Session Replay redacted](./img/session-replay-redacted.jpg) + _Make sure your Sentry Android SDK version is at least 7.15.0._ ## Mask by View Class From db409c45b9a4ea27a9b878fa15650aa85cf38863 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:22:25 +0200 Subject: [PATCH 07/27] Update docs/platforms/android/session-replay/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/index.mdx b/docs/platforms/android/session-replay/index.mdx index e7f2091a6dacf..426f222c11620 100644 --- a/docs/platforms/android/session-replay/index.mdx +++ b/docs/platforms/android/session-replay/index.mdx @@ -99,7 +99,7 @@ However, if you're working on a mobile app that's free of PII or other types of -If you encounter any other data not being masked 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). +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). From 9126d2a26e880ad42bc4b5f1eb0e896357e48fca Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:22:54 +0200 Subject: [PATCH 08/27] Update docs/platforms/android/session-replay/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/index.mdx b/docs/platforms/android/session-replay/index.mdx index 426f222c11620..ce9f106fa42aa 100644 --- a/docs/platforms/android/session-replay/index.mdx +++ b/docs/platforms/android/session-replay/index.mdx @@ -121,7 +121,7 @@ Errors that happen on the page while a replay is running will be linked to the r ## FAQ Q: Why are parts of my replay not masked? -A: Text fields, input fields, images, video players and webviews are all masked by default. Local assets, such as colors or vector drawables, are not masked due to their low likelihood of containing PII. If you encounter a view/component that should be masked by default, consider opening a [GitHub issue](https://github.com/getsentry/sentry-java/issues). +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). Q: Does Session Replay work with Jetpack Compose? A: Yes, by default text, input field and image composables should be masked. Masking within embedded android views (`AndroidView`) From 2095c52065f446e96338b64c04cdb280c1dd020a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:23:31 +0200 Subject: [PATCH 09/27] Update docs/platforms/android/session-replay/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/android/session-replay/index.mdx b/docs/platforms/android/session-replay/index.mdx index ce9f106fa42aa..fbf5c6c2b573b 100644 --- a/docs/platforms/android/session-replay/index.mdx +++ b/docs/platforms/android/session-replay/index.mdx @@ -124,8 +124,8 @@ Q: Why are parts of my replay not masked? 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). Q: Does Session Replay work with Jetpack Compose? -A: Yes, by default text, input field and image composables should be masked. Masking within embedded android views (`AndroidView`) -in Compose is currently not supported. If you encounter composables that are not masked but should be, consider opening a [GitHub issue](https://github.com/getsentry/sentry-java/issues). +A: Yes, by default, text, input field, and image composables should be masked. Masking within embedded Android views (`AndroidView`) +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). Q: What's the lowest version of Android supported? 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. From 69797d3f44ebff3fa16bfd1164f2e9521a4a4876 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:23:37 +0200 Subject: [PATCH 10/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 49591f8039d08..1aecaf4506717 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -32,7 +32,7 @@ You can choose which type of view you want to mask or unmask by using the `addMa 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. +- A `TextView` subclass (which normally would be masked) that you don't want to mask You can set the options like this: From da7f3ea51765161a98a3f47b45486fbb15582b09 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:23:45 +0200 Subject: [PATCH 11/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 1aecaf4506717..2c000550e1796 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -43,7 +43,7 @@ You can set the options like this: -If you're using a code obfuscation tool (R8/ProGuard), adjust your proguard rules accordingly so your custom view class names are not minified. +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. From 830fb6410777c02987574831c8e751f588f00619 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:23:51 +0200 Subject: [PATCH 12/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 2c000550e1796..b7888c7c8c07c 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -49,7 +49,7 @@ If you're using a code obfuscation tool (R8/ProGuard), adjust your proguard rule ### 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`, etc.) will also be masked. For example, you can do the following: +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 From c5e79291dcbb0abef89419b1d17e144ecb7df16f Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:27:22 +0200 Subject: [PATCH 13/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index b7888c7c8c07c..2d111b40d1f21 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -99,7 +99,7 @@ We also provide convenient extension functions for Kotlin: We only support masking specific composables in Jetpack Compose. Since composables don't have a concept of classes (they are all composable functions), masking by view class is not supported. -In this example, we want the "Hello" message to be captured in the replay (by default, all text composables are masked), but not the custom composable: +In the below example, 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 From 5acb078e7a595836c78b44c400c0ce2a1b87dbac Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 10:27:27 +0200 Subject: [PATCH 14/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 2d111b40d1f21..dfc88c4bd721f 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -118,7 +118,7 @@ Column( } ``` -Currently, we don't support masking anything within embedded android views (`AndroidView`), but you can still mask the entire view as follows: +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 From 80788c4d1d89d71c57ea80fb9943d5f83336d365 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 11:32:49 +0200 Subject: [PATCH 15/27] Fix formatting --- .../android/session-replay/privacy/index.mdx | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index dfc88c4bd721f..d0620f1419916 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -22,7 +22,10 @@ options.experimental.sessionReplay.maskAllText = false options.experimental.sessionReplay.maskAllImages = false ``` -![Session Replay unredacted](./img/session-replay.jpg) ![Session Replay redacted](./img/session-replay-redacted.jpg) +Session Replay Unmasked | Session Replay Masked +:-----------------------------:|:-----------------------------: +![](./img/session-replay.jpg) | ![](./img/session-replay-redacted.jpg) + _Make sure your Sentry Android SDK version is at least 7.15.0._ @@ -37,8 +40,8 @@ Let's say you have: You can set the options like this: ```kotlin - options.experimental.sessionReplay.addMaskViewClass("com.example.MyCustomView") - options.experimental.sessionReplay.addUnmaskViewClass("com.example.MyCustomTextView") +options.experimental.sessionReplay.addMaskViewClass("com.example.MyCustomView") +options.experimental.sessionReplay.addUnmaskViewClass("com.example.MyCustomTextView") ``` @@ -52,8 +55,8 @@ If you're using a code obfuscation tool (R8/ProGuard), adjust your proguard rule 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 +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 @@ -61,26 +64,28 @@ The masking behavior applies to classes and their subclasses. This means if you You can also choose to mask or unmask a specific view instance by using tags like this: ```xml - + ``` ```kotlin - view.tag = "sentry-mask|sentry-unmask" +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 - - - + + + + ``` ```kotlin @@ -90,9 +95,9 @@ If your view already has a tag assigned, you can set the masking tag by a sentry We also provide convenient extension functions for Kotlin: ```kotlin - view.sentryReplayMask() - // or - view.sentryReplayUnmask() +view.sentryReplayMask() +// or +view.sentryReplayUnmask() ``` ## Jetpack Compose From 887136a45b6ae03c6342d0bfe3ed3b081b660a8c Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 16:22:08 +0200 Subject: [PATCH 16/27] Fix and add masking behavior section --- .../android/session-replay/privacy/index.mdx | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index d0620f1419916..ee8248c97fde5 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -22,9 +22,9 @@ options.experimental.sessionReplay.maskAllText = false options.experimental.sessionReplay.maskAllImages = false ``` -Session Replay Unmasked | Session Replay Masked -:-----------------------------:|:-----------------------------: -![](./img/session-replay.jpg) | ![](./img/session-replay-redacted.jpg) +|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._ @@ -133,3 +133,22 @@ AndroidView( factory = { context -> ... } ) ``` + +## Masking Behavior + +Here are some general rules we follow when applying masking rules: + +### View Groups + +- When a `ViewGroup` is marked as masked, **all its child views inherit this behavior and will be masked too**, even if some of those child views would typically be ignored. This approach prioritizes safety and ensures no sensitive information is exposed unintentionally. + +- When a `ViewGroup` is marked as unmasked, **its child views do not automatically inherit its behavior**. Each child view must be explicitly marked as unmasked if you want to capture them in the replay. + +### Masking prioritization + +The following order determines how masking/unmasking rules are applied: + + 1. Check if a view is marked as `unmasked` via a tag/extension function/modifier + 2. Check if a view is marked as `masked` via a tag/extension 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` From ed730bcf81d723741832938c2b926954afc216f7 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 22 Oct 2024 17:37:37 +0200 Subject: [PATCH 17/27] Add missing images --- .../privacy/img/session-replay-redacted.jpg | Bin 0 -> 22789 bytes .../privacy/img/session-replay.jpg | Bin 0 -> 42757 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/platforms/android/session-replay/privacy/img/session-replay-redacted.jpg create mode 100644 docs/platforms/android/session-replay/privacy/img/session-replay.jpg diff --git a/docs/platforms/android/session-replay/privacy/img/session-replay-redacted.jpg b/docs/platforms/android/session-replay/privacy/img/session-replay-redacted.jpg new file mode 100644 index 0000000000000000000000000000000000000000..821578adab8704e0018a4fc578dfcd5b99a5c2fe GIT binary patch literal 22789 zcmeIa2UJwc(l)#S6+{660VOI?vSbhtl`KiZkaNz+kh9^C9dJN0f(&`cAUTO-5RjaM zgt}}dw2Jq(}B|o;KoxiNihHg1prWx zf57P^%7CP>u+B3DIWb9T(I1Q^0GTe`2LLN;d$5A|lRK(v>UYp5erTNW^bG8tpXGm% zkhr^jXXpUX&HNWK|El_`p^=>dQeYkVPYp&IM>=~GN#8X2LEk&0^?%R;XS9?3b94UzOcli$($zoQMFgU{sOAY}xsEFI2louxC6uNzr|6p=Xw@}Cs20~7#p z;K^D0k!57EfdK&T4gjFN{Z*$Q1pvj~0B~#QR~_{S0KoYT0E#+()%}Xeb3L%$ceqQ) zPgG-L0N6|g04y~C!2b#Wm>S=C$dAA9?GBPfiuB6{`DX%H0!F|cKoYP93;-4+#SYvD z*Z}U+VL%wTa_RDw%a^WPxqJm3{R#%=4NT0dS21s5<6OT%bo16NqML+-#AGxS#3WRt zgoJmP?oiRv(KFEBreMC$eD6NZJ^FiRASmeQ=$IIo_?VdZ_lOCJ@BJUA(@y{{2HIPc z4`?Wq04gpD8ZOFd9YA(AoGzoBjl}bWhV&L40|oUelC60IKtV%6MZbO-BE}Oi9qEblcJ9I*#$I6^~w&0fudEFS4>|yzn99%qhi3L>D zPaI%LHS65^M)owXK7Rg2D`H^y8xo!L%q}Y0?~Q*)M+OPW<;O+3hBS8O%q6t%-l3r4 zqFutfj5LXVlTbl1fq?z7Ei|w53a1|UWeBW>gYw(@2Gx`N(;?tG8WI^74Hpms=5$f| zt4hvW_dlMuTDfDu^PaN=jTSLXz|wP|gh6dkB31z+<}JqsE2A`nS2|qvGsh43oDXoV8%{J< z+fNv4U)^}kQGM6Dnrl`qP$l44tZ!;`&nk68wkH*LcUsnV(d?%Tf?J)Qf+DJ@C0B*cjrFv(0mc%p+MLCJik z=u~C(3SFh*SVV#WDxUs^iL#zYwXVkYlJLBKUvB0X>afTV!*qoJ*EA4sLVyWdT5vww42Q-VAg*WezZ2N(Q5W}%zmWsza8qY!sc2FYTl^-Cr-^o)DSdI@2gkae4T7 z#}5(s@%ovDX1756ox?MjD`y%kW^r0 zq8ZWIsV9@qG^%?QPvYx*zOZV?yZL^kq+<;9Tt1HU16JeCt~7s{$XV|$Om1E>`Gl6> zik#a2n9fnXT^?JX0wB3vFFca_m98G^lO~9zzyp&RCK13%j_r?1e=Ok;z1`k$LFJf0 z`C4iEM;7w>$2`86j_8oxDl7wxe_km~7nDK5xqR0J-xV3{2vqMHK#+kSHb?yi^zVP-az^MTPZQjm1b zn17I}U;YiaDWEOfT|bS{@dEwH&WB%UKdAFiVs5?~MZn{i5!BpzuG>f7>N-yPi8ec0 zRL{nQ{y%D+ms>L38H`@PR#X`Hn4MY#?^RPY%~-S3-(zQiAa-UZt78ZS?tV7byBzp* zST;<@TCwzY`A}MvskJse{@AoewzdUg#E@{aHZf&y_XR4)|8(yQ37?46PTyp`uU8tb;CsFdlUaNYtl zrYS?Zp}XI{352{+izJNIe1nykGV*22ApxR$Sty6@K#oV(D?HxaeblpW6xw(k=APW` z3DXV!T!gba?XWiEdNbY%{-=Mj&P zj4{Z=56UlXZ7)c-|7;(&6;|CNjk~X0b25tEw1a=ilOWg2NjP8A3HGp8V=8UT?+9cQ zlqgL`e_#BY2Kt^oKh=dwv+WOwBrYYTchISx{@#Y+RZ(^CDPr9P#@VD_fPxnt z6latfyPz^z{j61uuPdkCGa&^(IU_!1{Lj#5)tlSHJQ;Vc7lyuPI96FiqMFam?p>Jw zoyRWW`F6=V0Vl%DhI3D=2@ZWCAE=ieRQ@Xu`C04?- z;Cb0)N7lA259(bj*PhaKrABC`zmPWne%J%aEv)k+7I zvm9QPfLA9teO1QB0VpU>u+K;Kd49V(L1*P*?ct`^yDbb3uP4<*9=97%$Vm*sqP5g42b5BL&zt~6 z6_%X}9<2*(8D-oj#8c5dd-h?|@@H|p!}Q5xJ0lc6#KS5hidL-gU}U@&ui;_J=hM{9J)a~-lBjsBzLHhQ&3TKS79 zw3(9rGbvta;XYRmCXTCb@Hd|Vyypbp10Nx$_S?G!M$Xj@If=q(?(3d9eq_i%#y&qM z9Ikt=#gb(XYO`)+%zynfEl+fqil@AF$h42u?wlom0B3bTcgO=%fma8^rt>l*jOv~7A_ z3LMsnH?bmA$j?JWAL#9^*$YzoBDOHaW@9OA1YqyX+(8Zu6geG90xQOeC?U{DKx~!{ zIN=#kAZ{vSLMzs5&2d`+ht>GO1Gfask0Ql8~5!+L6a4V}b7TZbm|W-pmO!p*qCuDJk!pdMn`} zFb0nq&*_xq^}QR`Ppvy}Y*8w8$6C<}#iu^}$P&Cp-i^kQPhvI841Qa^YaOkOwVcbZ zap#BBwZF^8SLjkz>Ml}NdXi&4Hev>~*7j7``n}6fH1nCa5?09iFiT z4_~vq<+4E_?oHTi$!||8y7C(5A!XV+Y><55{?;TzFeWopZ}`I`>$z0ZZjEm|u9CC7 zWgzw_I(_pj=b%&jUc9r1)nEr@gG50XhFvI88p0(b)V+ z8NT>4SpX&f6cDFaacwvZJq1Fx)Ja&k!HE7$n{=TARy=+IK>x#^ssRA@v(Iv!N0?Ma z=HX2tKH1)zd>ew@`hvt6bwQ%CItfZeZm6|E9gk;2<%_IHS&LG#qBi=Pubc1G8?cC& z>(qG*WpU4f)4F`x@M@K~oN}3Xm$%8yxNvk;Z3pKCy3DzQfAC-T#n|yFnLU{g{Tot` zVKUEp$3Epw6?}C`>JfaY*J$!#OEPWf;m6^qmc*wx>Q-N7o(d%)5C6S69&jVL9=3xFtK;U)V)|*%h#~^1<|8rga-&o9bIuaqale)GNrL_&JQ~& zBkdsKXQuzsE$`MV>)HL|W%uBW6awrm17nRa=J}a&L{cYhnpwwrQ_0UAcD!-FoQM4A zXWV{ymiwY)YWz>6iAdf4$-$t{s8hin=Pf^PrToAnP208eAd}#HjZbK`xSU(W=!8L= z9Bjw7;)9``V;4J{0RmZ<;>~D#<&IBi0%z-Yf0{^Fc(%Jdj2>cDYrNnV1u2D2^*+e~ zm#X0p2Lx2~7fJ}m4w9u*SG9#YmRNK%%VOm%&o-@ao$Oi$n{bPp<*XGLTD+Dned-IZrZgobc{wEaf_93wkp21bmPnCm+|t5p&D$1 z4p|&64-!xOH9X(*nzf}Po>Rb%Xd~gmLP&ngCpU(+?11#3^k|8Q+y0E5@&tTD{x@Wv zn}t6EIE((Y!T(T+SxmFkq|T%v&j^Q4fhNTb#J7q=6;6`NuP!&iAm)=`Hc&rb+ze3~4Exb+9ms5SL^{{`Gysf>PHMF+wb9ABYF)z2oz2z2+ z%za!aqM(0wtRh>X?YCV+Y5!g*->s!?vbZ^h90vC}r>HgqU86&n+KPq)h^CMRa$O|6 z+}qb%jFuLnQ5kCF5Ne)m{P?HD7HWVW*x~vSwi;Hdd@%;b&5$^`0Oe zn~~K%@JLP@)Z?p`yBq!xOdGIJS<-f}=2uuf&8Id}c#AtS?qR)|X@QkeMj=D`+9@Cw z-wC!Itt)eRDos~F)zqwkH_6A+Xj9ss)qf&j%oJ-L>*PKQNiSmCj0$)@8z^EkwIsGb zQ@+^27@A0gZC*`L``YN$tL6gAg2~d1V8+m$xawDScdb8Lu+zMH+Q1^SQmPp@XFHm- znpeQPujU#3d~&18Km}uO@N*(|zy_!JX#4nTdP1QBY%o0qBpprDdAt}~EprOIBC=D9 znh7=*H>q`H5onj|^E$zweURl}$hH*V>>+(LR7?wZCG^}r7%SRM z(JgKv7#wfy@0ZQe_RNnr9430Mk`(L2jtOSnloyMP;~8Du+GFvl-rln48>k9gG0$L! zJvC2Og-IrY3zx+udNjiL2$#B$_kOL*ZVwnFHq!$R45fP8PTq;`@yy<*=#o03{&)&h zzCP}YJ;q$h_RGMFkv?MeN))3O<&sw90ka^64*IIU2&s+_>pbW`@Lgj5G}c$LwvzMS z;<$DPa#FaJ&+^vBpd+s#jd4gxKSI-xQ@+H(YWD)JeKSfcJ^Wg z98>4lPJ$**fm2}q6j-F8hP(kNU;M+k|9z338Iw>YNjj=E#2_y$9np1Evi-JqpvU1x zp+BC;Y;v2s88{_>5}TV=4vo+}dfq>}q(~8>#T{VsB4Q+BBVEe0lf8;}Dym&#=-5Hz z6tM7juG&l^$-AFkpJJNLiq{aG64gtpyqG~8;EX2_XizT|JxkLPjp+JD%y+BDEicy3 zFS~51KX&_;-pqRLVsu&xrAfrM8uL1MTA`u?bE3%5zS_-TI|K2=SjdbM-o_0j)gBJT zBsIcDC#tBr=_3#1YNG8G-YDtolF=D3S`+(Gvxe+QzZ5HzIwsX`kRV6?=pIpre(j2B zZf{DJM{g@vEzPG@^f%#j<+D>I=~r6T)3bwu(kh-C5J-dIyjfeSJ?z~{d{^@Dp1yB5S`gH&di7R|-Q^;pu7t4G}JB@evsn0RUZN>iSNc4Mz%-V#HejXB?% zT`#W3o`KfxZB?Ql8)m;BK!2c#^M|*WUKYuu%RgCQgd4tGBAHHoN&3Z5BMcX$fDm%E zy(w@vmjhmST<-X3+y7t3fa4+iJnc_HsJ3EG1Uoz`MYtj}127lr3O zpW5O5n=8X;&tJ=36iCmp{tNsc4n@lnes}hjp}u6nYlhj$Ax=q_A+SppY+=?SAaUjq z&z(s$vll-{$?;N_#*#UK3pnUlLNdcsO=u5ENdL_(3IL!<(tsyun-p(Q(j*@!326!4 z5E6ZKh2aPI#2d~$)8$zDkMrrw0S}t=-mggB8szKu_flT!hFXJUjhJHMSO%~7F2{3K zID`?w;WK0n)sk037Th$)Xk=ppe0@}@4k4KF{Yjs>?0v_>btCZl_YkN{gG)|jXWr> z=WkPN%4eHfXj}QEpx$2084w8C0SeFSf(1H=aHdsI=(Ed92XVa*yUC!j*6N93b=vq1(ue=KDRav|^pD^wrtG#J%(#sZG-=xaXx8 z!lkhJlSLj*Es9FXVE^QxTfJL?d3k)AGo`@(NTK21T=&rWS5Ts zC-?3zR?;U7r!#G_@3{9-$=Zm-*W|yWN&~)jqMb)Q)~01buA#vHyGjCJCL%s~DgUY+ z$fkVm3HU)ysML?SM|V^3}X_yN=wb40RvO|%=?gP2uOMDs8af)BnsS1QVQIeTS?Y%LC94O7Nb#XI_>ti7b5fy8-6|_s#yd7(Yn@lbUlYkV?C}Yc^L~8?J(TL$c2$CH&9bR zKV?=+fDePRYMYA2O=eMLcn7g|Z2Dmn`uy{=dGDVS>d)?>rh*@ER)f3%YNQOxdH0<6 z*B#V=?!@SPPD7CF%YcA>7#rD}0Oc3=EL-U3J4t8^QXpAkc>#6i+><51<kWSe+uOsB=&`ELIx%Yx`W=PVmK^SWq zFWEsVr)m#`Uk72#k+?PbZbEu4H-t@0z2a*a+xT{za3LYKh&uIj{T%4og+!tQifytp z??jMoafP$jyAc9MQtwId%o^*&JA^_8o z=a5rrvO&jTq}rr>)G5(lH}Mq_17jj26C~%+Y-@Cv&7f9*E}@15TS}ozk_?ZJ%FvdQ zF>YsCq&jdUWBaZ<7wf|Pc*N_3Q@}+Wp_CHqI){U89&~@%QC9iQm>mupelOf93o*W2 z(X27~(akG=i^e9P`+ZH9!?CBQoZNCy>#E#pd6KU@G1B8$eRX#s!sZg0`w%@s4;_yjC6r;Ox>?*oW zhyeQ(KgJcmS z@uNa2B0tqSR}igV!m1c$ozQZowl?{x@{dA~QWxjX)qb|ZtbO9FdE$nSI$$sR6Rq2F z3%iZ(Uo3Y;-EH9`bA?~Pg?y`%6(dUB^&lAnQU1>LmO5yVtT>m#wiY_Z`@EMz`|O`i z0jF-{Dq?p$^h-a4gP=-oMY+CZdFcL9t4RHkuX-ywh@&@ds^bxsC+VPz{V1wu^`yDJ@?oO$=$TSz-xr5DkwGzo(rwU70DO@sS7s z=MO%8PHRlNXCGr>Gr3}Jno_18nQ|<20|3AOW7mH#iGw!HJmH8-zd7j8Ml9w`TzY}5 zrb<5G)By>hK6#)MD!QY%P7R=L-l~s(3r`9%FE@tKkGq!oE4&ez(s3%uyUN~N1L?^R zCpI&DHJs+2sb30FPbu3GnUt!WISde&5xOwE>8=bcQ2n*9&(zkrt1MJ5G4Vf1mN&^rc;!MMxaw{N zK3UYp_<#)RKc~O>-9z1^|4pQS%_BD5SY%o)WC7GxWzBU0+FO|A0JkrpUal8Y>Jul? zdegwI)2n~npNgw**`U9~^d^+N_Z0YcKlzKaVS~vbPS1=i%R^5pdgN|l2E9UC*ce<%6Z3nF(+w=A^fRNJ5W$b zdP88#S~NmG1AQ~5O)~r>Q}3$BV3g#JEkw zLOx4G45sN9H`$_C{kmHU5l%7K7LV8tK2C>xHSg#WLSJE`+;(lsbX7B7q_;3gw`b$I zy{gZ)qNy|kIvLVV2%uSE6Q5VI1fcgBj43dMO`8#D;L|0s(&<761AMIv~ncBg6?ms@~~=+q-vv z)cn__Uvq*|HV0T{%5FbKQB;Nz21Q4uL}R|~q7|FYL46WHFy)wwfVjnN z!mZ{>eziNO0)Z~m8)TV=8Xa_gD~2yHHks!_>m2i-HUe=}g&_b{Q*oRe?oh*j)&Fkj z3Kn?>$@U>-2+&^oHnJCjna0cnc+77bZ%KYDmq!M?z$IyYG|eccjm~F91R3zQ+0a_Y zgm4?qIFdpy-zJRhL8aSwS-;Ur#VebyWI5?& zsibD?9++oVg@JOU7<`KkV;Q%tZ|^0}Y;5gsMQzGAhIe)g-9`=rO5Zc)#byKqHuY4G z_=73kptzV{uGR4CT+i}Y$^BqikVq(Ax+<2>O$pPU(RnY=x8G`LA8`Q|ggZbLleLCQ z(Z=PA9?P+08GL``WzF36!(pl~{JPd8Lccj;%r3co^4$`@(21^n-F|zgNIcT<)5MmK zhZS^|ESCo>{xkn2JBP{%;e*5r9T~j~sOK)V4~v?%um?zdI=+#;;wu|lzkA$yp_7t( z0i|E!GGBZ3K4k!Lt3I()XVY<6Z{@>$fe;x*qC_BAVWp4&p~)T za*q$BS!ba=rfulTg&&nhOHc^VGfO>*ZiRV(EF<3*1RUjnK+_^mFmv?~Uo)*CIzG{j z9~ns!RKBGYFtbPa=w25ZB7l6&SnpQd^)|3)IOgo*Y<4yVYEKeWM=`6hxPncUd7k9d z${0xh4dDnWbWEmUYo{8q0}>7mh(8r_|IU67U%JLw=ljXTznFT_=jf3;_9BLIsw+F? z!C;R4HVm8iPI56?{NcO|DET6HDao3W_y&SLsYSl$4jRE33>N568paBXF7FOWp_t@O zhYLwI-|7%`z;c5U>^v(>tJ-O(TEQp-rfM^VM8=mFJ5K@EW`r~y-Fv-5TI72r%E3o{ za+`YW@2nHCx6@AnpTtvOq`3 zIN$Yl*p)G4XM;9n$nMeI{0h&e>U1I8{#p#%fQ7rUbY|se7-SYO%q78tca2^yHqs6G z&R;IjS92V>?lV}Bwlt|f#Z`E}NW^?Ad7&;jW^nAvF{^=#m^pK2lV|V!sY!LjraAdJ z@nGwMPu{-H^UaNSCPntW8zG*UJ04Gou&z< zD3s>i53jC>_B|(pDt4V-R$m(!laKZ-sKDCSZrFU&!@`F%ltSt*r86cY8i?^cZum1# z!;)i9Ms_oz)))%PJS1uIwLIegH154@bFWSK!Y3k9(jFB)+%$MbonPEmp$E!Dr5NTR zU(%~8`n%bg(B6VtI=qH#5wSwWkrIf}e1&OoLa18g?bqB|8Vs4s6#41!M2$gCrA&*V zYW7iA5AS2?GGTL|d^z=!}iOtpxWVbw> zZkW;*L7r@?G&M<2$q0(eTL}vp4-La7u#p2NY;H&U6q!X`n@x?L0gFYH28qn>jh_Nu zf`T$qGZ`syusBuIDJRD6;MvwNxHd zW!GjJxvF{!@TnRQdW$HPuP_TrW9u_y$q-0ct7J1!PG;?;aLBV%5)epOVMeE0m?v5c zN(|^iwhz=(AN#xN1Z9aRd9>E0RcNZXeaVb4`cQxWRpIg|k4$J%%LBaJfHlkDTJr-F~`d7_Zl2p;oe=0(Dr(eoh{$(fU0eg>GCmQL$2+rY$m(* z>GaoxVh@pf1k@7Kr4{}T{kC-7&Uuas*DhCb9xX^p2Z?>!k3&3&P@F0yz*{zk<=`=7 zjoXy?(3P&`PkywzBvut?q*9}hWeE>5W|*Ss&t_h#cd8zB&TV?nNWwv>LMgGW!c{RJ zp|hV7y4+}47Nx};8wA3a-gD`yu749!RO|9#$itD3^05o&<&49Dmtr_k9WURc~godU7`Cmy&`pn zKuBS>;bPiSUIf8aKccGRnEq*8hnZWAda0Z3@nk*g`* zO*6{L^A&Y2JlkX+nggddRxAdxT&bed!LUvGy-=^mLsw)@&`nX}Lf*g2O_I+D^Mj|q zDIVSOxYXEp#<+c^hoN(cU80#ffJdTZ&@MV4efwU>tz#vFUp_O5*k~QW6p3xM)-O!TPve{o1t|e z?b&TmOD}S_WBN(KnG4rr4za&pGHswNl+UV62it<_*iD6JdG#S{?zVYBu46M6@&v70 zTcL*IUmahbg#ZZPHGp*3+va6oFypu}G$90$&w?Ok~ zluETB(nfMg+_z#FlPxVJwd&>)6?P7PCyL(mFyCgL|It~i0px4Q7a0F}MwoqkXHJ)5 zk{qalK2Q9@D6g{;T+Z z85{t(98_?P>FI-r8hP!Wu)u(63-YCi=xxy_I9j=0yk4(qo2}@b4Rsp@9czxiA+EvuDt#&e(H#9XGC%#Y;L!MAVq z<+0kuR!z(0+24vN)WFFf(k9_>(l>MWs|J! zbiE8HVRWZCYo&n+(edv*`1I;kHs;|y^9AjY#~kv@P7mn$K1W8zNad%b!C6TG6oU30 z%nX5m4A+b>70KJ+kCp+4>VvTG5PLiAbXPHWU}H<*+LM^)y}N41Tzov{im0hSXcC{C z{ElyFqW2k`uyl;#YvoJKkC+g|FQqZx*QyMftoK+GSG5ZHeE3I&o1fB0xIDtWu*AM) zEEnvXU;g_5uX6HxoGsF@66cda&#f)`Lz4TQ)Q!a$=ZAb?zUZJr+lO?m97z`15iHDY zvYbcP(>hfM2PS~)O1~QjDA|?Vr@*skUaMY5q-F*7ho-6FmLw@5w0z3}38XtB)dU3a zh@3XBNi%~LZtA)js&Q7{BPsmb3)S}kbnE$FNMu*%k@s(x26g1e8>VR3j)Bzh2(;xA z_^tVAiC$2)R2VB5?$P4&$Ys`A-*zc-PKYPlP~U*r7k@PP9T5C|=DYHJY9n=`zeDwX z?tA=wR(v6WvH5-OGx|O&;-LzBpZjiq|KeYI@q1O2|GkP8W(}gH9~Sjj6IOpW!81uW zUW)Xe+_HPzQ$O+Ffu~S$kvD(lTiEMGezYA4GwAu7utA@%5#95m@ zh%EQx;UtsRsuTQO%wKJqrG~bBN4zroIz6z&xAb@OthNm2rppg!mUO+dMJ?rFsg#M& ze)P`|6c^6!=09}CZ-&UT%C`u-lAP~kgfmzOb~iLKDu_$@L!7FXLG+a=UJF87LQO_6 zMJ4Y0Tpb@fPUsLO2k1ZZvlrG3&@l4uBS@Zfz6xaDqr8DX{YhgBg{H;KX{E_B-?VNGJAvUTK}NVsY`Mk*k zM8-?#pJL9|$5`6>a9;AvMh=E%qBI{<<(BiPKD;y@%`2|wXr1eRwVG4)FEj$NbJ6M6 zgFY{h>h9xvntmhm9xSU_r#jS0{xC2@-nG~otZKM~FObw9i69T|;D;&o<@F7dLoMjWTo(f=E+x3u zm)|*2kKUt1w1%GGCpN2-n@!e`hy zjJQPQouB9BT71fWzCqay2sFyt2F1?G$hEhOhs&KzRpa614<<(=5B8?OA)RtJkq3LH z|Hi>yG($vC{P1P(Z6z=0-61++Pe@OJ%z|-i^u3Y!^r`oo$j1$cYHSZ^b_z^4 zE(A3H!}K)y>o4|mw-(ybKWvflH9W9;`I9l>io@0&Ymmx&E^vix!KVlo*x8%A$fMuE zp(Y);C9#_~zFsOF-B4h*>_!{X4zp(FVv_Oqt0<<_ay?#Z$!Iqid$-)Yl8I8da4$za z2~r^97m@Lv1iD9Qm(AR~mF`qy;TVIF>*>>*q$IJZFP>pjjXM%#p7VftVVBt8xWH5X zWc<*POWV=ofwQQC&Q5^+_%~3sa^7~%0(SqWOd(hRget8dDIrMGj7AFD8U`h31KSq% zQ_>upwFj6)UiR5lCjQ#W6%`ibj9U)7s$rL?qT@tC37gEJJmCQoYI1B_iF)rF$RMA{ zY@QOkDnBlTP1*;ESGKxUwv{%;YPwgL8i$LW1PYO`(vUMMK=vZQ8o=yoR*rB2H}P3 zpi&J}Zj~*?Y*D(;dRo+{8{@j_y`+!p@6zq1j*=v4L=*@uPBM(I>g&`urKP2OZj`k% z#zFLb^E%op_x)&t`{1nK$9Bi%(8j^bj<1X|I(x!zoXu|5h zsr{3wx0G4sKaqr;GvD++o*7Il1(^S>b-CND<9V|C04eghSs`)5M{jZPCN=OVgu`QKYd zMN*XIdSInBSF;auFi?A!mKMDe6qV8JO2-%xhCe?ewL0kSt;{qew2(?d982r~TJ;O! z5J+%ON=#0)h!K~;;@4_OziC>hb@_3CBc5iTwBsS}pkyr90LQK-+T;n3>@9dZER-rFC z1?=m-xQyBX#H1h2=jEHb-ioGaGik1jQ2!?6@x~`FH7xR(zvh3MgBdVCq$BzoG*eL| zl|At)AfeD6Do3$g$yy%eF)u564seaYvMWZAMg6olMC=Q z+|8hordj4eDJU*Wb)cjk%?f89Y&a;$&~vKMqt!1$f25?s$pf`1y4M4?tDM+%NgSMq z%UT^UQ=<56=z6i1Kt5kj$r|#PuOwYH(~4<^aF|?4o?Meeu8w8<%+ZlX_HS$v1nukt z`p92P`<_q;lr`?Gw1&2N6}+n^iWs-GsT!I^9{HJKNk&!UlmwM2(6kyDOc|6%M8xKX zz*AZcNy-#BV@@*P?^hd5f4KN{GPIjDb2JZc>ydFH4;jgGz|tU^5lqm@(fW3XHWee& z?#W9@%ju-BEydniPqCEu`yt|9%&lL*_Zd^(E2)$*1nPwE$1l{k>GdneN(*jDkB#g} z%XNTP;eG+|V#-@7s4UuUu0;f=fI@nX>u3L_rIOg~IdRqrH`;6ceT8=m*M0Kg!Q-Ruc2*BttK85cIXrV;@@~!((3ZDyQ4^N!0=(UJ$wNi+_y{-0&sj>P0yOB>)=>v8OF|6h{smaYNuXIc{h%@ z&tAEWk`*s8j7Tz!iBW0oFC(g9pdJ=z`l+$~;MN|MW`EXk^1IBut|R5pqXq<}u76C? z4WMV_%*stWwU2fZIpNVff-cId3b`ncD{qp83!=H+<7aZkT-Rt(ze&>hc+lW05A1b* z8M=3p!VOD{=$2<8W=Z~)~I5)m~V){&G3HH?nqsdUjyZ%BTI`uaQC zmF;Jas@nt;#qU1e`+*i6?Gqi>$`r?ovdRcfN zf~&)Zn2zhXnCOO)jDtK+iWL)MZ7LpTKT&YK?v4=p7Kq!sPf)JrxK}2@A!6NXNpe`Ne;}0}#i2I%{Z<1$U4c8TGr)($y(Y`MXTunT;sA z5%QN^0TjT>_DixIXEBsQaE^reG@qeCBP6z)#fOX=( literal 0 HcmV?d00001 diff --git a/docs/platforms/android/session-replay/privacy/img/session-replay.jpg b/docs/platforms/android/session-replay/privacy/img/session-replay.jpg new file mode 100644 index 0000000000000000000000000000000000000000..998822d328946a9e1a84c0b8d0a19f29686b8e1a GIT binary patch literal 42757 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 jjYELENQF$?N-7D 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 literal 0 HcmV?d00001 From 73c4161f9e6b9685e275129f7d5602deac0900bd Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:06:26 +0200 Subject: [PATCH 18/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index ee8248c97fde5..7045b90f0a80c 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -7,9 +7,8 @@ description: "Learn how to mask parts of your app's data in Session Replay." -Before publising an App with Session Replay enabled, make sure to test it thoroughly to ensure that no sensitive data is exposed. +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. -If you choose to use custom masking in your Session Replays, you may accidentally expose sensitive customer data. Be sure to double-check what you choose to expose. From e5c7f5eb24b58e53ebaf8b3768255b6fc3dc66d9 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:06:36 +0200 Subject: [PATCH 19/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 7045b90f0a80c..fb02e8eb7a784 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -12,7 +12,7 @@ Using custom masking in your Session Replays may accidentally expose sensitive c -By default, our Session Replay SDK masks all text content, images, webviews and user input. This helps ensure that no sensitive data will be exposed. You can also manually choose which parts of your app's data you want to mask by using the different options listed below. +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): From 7a304db5d891acdee55c3b6870ebda4bb99a8215 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:07:01 +0200 Subject: [PATCH 20/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index fb02e8eb7a784..5975184ea4ce1 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -101,9 +101,9 @@ view.sentryReplayUnmask() ## Jetpack Compose -We only support masking specific composables in Jetpack Compose. Since composables don't have a concept of classes (they are all composable functions), masking by view class is not supported. +We only support masking specific composables in Jetpack Compose. Since composables are functions, not classes, masking by view class isn't possible. -In the below example, we want the "Hello" message to be captured in the replay, but not the custom composable. (By default, all text composables are masked.) +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 From 0a751a93a04d9672b3faae8daae480e863f18cc5 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:07:13 +0200 Subject: [PATCH 21/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 5975184ea4ce1..b8715ebf5d607 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -133,7 +133,7 @@ AndroidView( ) ``` -## Masking Behavior +## General Masking Rules Here are some general rules we follow when applying masking rules: From 57bca3a268ea2152a2adc4f7c39a709e64d5c85d Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:07:23 +0200 Subject: [PATCH 22/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index b8715ebf5d607..d695d95d5f7ea 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -135,7 +135,6 @@ AndroidView( ## General Masking Rules -Here are some general rules we follow when applying masking rules: ### View Groups From 10c599e4447b4f7fee0d8beed14d473facc390df Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:08:07 +0200 Subject: [PATCH 23/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index d695d95d5f7ea..5d068594a416c 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -138,9 +138,9 @@ AndroidView( ### View Groups -- When a `ViewGroup` is marked as masked, **all its child views inherit this behavior and will be masked too**, even if some of those child views would typically be ignored. This approach prioritizes safety and ensures no sensitive information is exposed unintentionally. +- If a `ViewGroup` is marked as masked, **all its child views will also be masked**, even if some views would normally be ignored. This prioritizes safety and ensures no sensitive information is unintentionally exposed. -- When a `ViewGroup` is marked as unmasked, **its child views do not automatically inherit its behavior**. Each child view must be explicitly marked as unmasked if you want to capture them in the replay. +- 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 prioritization From 45bf9c8e34f30271a7958dc7795d7a7a48317d8c Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:08:18 +0200 Subject: [PATCH 24/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 5d068594a416c..36b01af906622 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -142,7 +142,7 @@ AndroidView( - 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 prioritization +### Masking Priority The following order determines how masking/unmasking rules are applied: From 3ddf363c46584811b41564e59db68add70802457 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:08:32 +0200 Subject: [PATCH 25/27] Update docs/platforms/android/session-replay/privacy/index.mdx Co-authored-by: Liza Mock --- .../platforms/android/session-replay/privacy/index.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 36b01af906622..20d63805bc620 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -144,9 +144,9 @@ AndroidView( ### Masking Priority -The following order determines how masking/unmasking rules are applied: +Masking and unmasking rules are applied in the following order: - 1. Check if a view is marked as `unmasked` via a tag/extension function/modifier - 2. Check if a view is marked as `masked` via a tag/extension 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` + 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`. From 0ba684d0404ae748f4fd5ee5b4bdd8a30acbfb7a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:09:18 +0200 Subject: [PATCH 26/27] Update docs/platforms/android/session-replay/privacy/index.mdx --- docs/platforms/android/session-replay/privacy/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 20d63805bc620..2d79f43f286ac 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -138,7 +138,7 @@ AndroidView( ### View Groups -- If a `ViewGroup` is marked as masked, **all its child views will also be masked**, even if some views would normally be ignored. This prioritizes safety and ensures no sensitive information is unintentionally exposed. +- 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. From 81008d549c5bf45af31a84435d0976d11962386b Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 23 Oct 2024 11:40:29 +0200 Subject: [PATCH 27/27] Add old way of disabling redaction --- docs/platforms/android/session-replay/index.mdx | 3 +++ docs/platforms/android/session-replay/privacy/index.mdx | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/platforms/android/session-replay/index.mdx b/docs/platforms/android/session-replay/index.mdx index fbf5c6c2b573b..41cc5b6d7438b 100644 --- a/docs/platforms/android/session-replay/index.mdx +++ b/docs/platforms/android/session-replay/index.mdx @@ -108,6 +108,9 @@ To disable masking altogether (not to be used on applications with sensitive dat ```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 ``` ## Error Linking diff --git a/docs/platforms/android/session-replay/privacy/index.mdx b/docs/platforms/android/session-replay/privacy/index.mdx index 2d79f43f286ac..77bd56d53199d 100644 --- a/docs/platforms/android/session-replay/privacy/index.mdx +++ b/docs/platforms/android/session-replay/privacy/index.mdx @@ -19,6 +19,9 @@ To disable the default masking behavior (not to be used on applications with sen ```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 | @@ -101,7 +104,7 @@ 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. +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.) @@ -142,7 +145,7 @@ AndroidView( - 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 Priority Masking and unmasking rules are applied in the following order: