Skip to content

Commit f181458

Browse files
committed
Merge branch 'master' into feat-reorder-sidebar
2 parents 87fc040 + e8bfe3f commit f181458

File tree

33 files changed

+752
-541
lines changed

33 files changed

+752
-541
lines changed

apps/changelog/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"@radix-ui/react-icons": "^1.3.0",
2222
"@radix-ui/react-toolbar": "^1.0.4",
2323
"@radix-ui/themes": "^2.0.3",
24-
"@sentry/nextjs": "8.34.0",
24+
"@sentry/nextjs": "8.36.0-beta.0",
2525
"@spotlightjs/spotlight": "^2.1.1",
2626
"next": "15.0.0-rc.1",
2727
"next-auth": "^4.24.5",
@@ -63,4 +63,4 @@
6363
"@types/react": "npm:[email protected]",
6464
"@types/react-dom": "npm:[email protected]"
6565
}
66-
}
66+
}

develop-docs/backend/api/public.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ within that endpoint can change at any time. This is a relic from migrating the
436436
our prior approach. Note that, going forward, we recommend new endpoints always provide response
437437
schema.
438438

439-
** Can customers use private endpoints?**
439+
**Can customers use private endpoints?**
440440

441441
Yes, if they wish. However private endpoints are liable to change without notice at any time,
442442
potentially breaking the customer's code. Please be careful using them.

develop-docs/sdk/philosophy.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ sidebar_order: 2
55

66
This document sets some general guidance for how to approach SDK development at Sentry. It should aid both internal and external developers to understand what motivations go into the design of the SDKs and why we're deciding in certain ways.
77

8+
## Trust is #1
9+
10+
Sentry’s mission is to “Enable developers to ship with confidence” and their journey always starts with our SDKs. Above everything else, we need to make sure that our customers can rely on the stability of our SDKs because they depend on them. We are committed to having the most stable SDKs on the market and will own up to our mistakes with transparency and clarity.
11+
812
## Dependencies Cost
913

1014
Dependencies come with a cost and that cost is high. Every dependency we use increases the surface area of the SDK and add more licensing, maintenance and security concerns. We understand that dependencies are necessary for supporting integrations, but dependencies must never be required for the base line functionality of an SDK. Obviously every rule also has exceptions and on some platforms we won't be able to work without a base level of dependencies. A good example is Python where we require an external library for HTTP requests to safely send HTTP requests.

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,34 +94,41 @@ 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
114117

115-
Errors that happen on the page while a replay is running will be linked to the replay, making it possible to jump between related issues and replays. However, it's **possible** that in some cases the error count reported on the **Replays Details** page won't match the actual errors that have been captured. That's because errors can be lost, and while this is uncommon, there are a few reasons why it could happen:
118+
Errors that happen while a replay is running will be linked to the replay, making it possible to jump between related issues and replays. However, it's **possible** that in some cases the error count reported on the **Replays Details** page won't match the actual errors that have been captured. That's because errors can be lost, and while this is uncommon, there are a few reasons why it could happen:
116119

117120
- The replay was rate-limited and couldn't be accepted.
118121
- The replay was deleted by a member of your org.
119122
- There were network errors and the replay wasn't saved.
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`.

docs/platforms/apple/common/configuration/app-hangs.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ This feature is experimental and may have bugs.
139139

140140
</Note>
141141

142-
As of version 8.37.0, you can enable AppHangsV2, which is available on iOS and tvOS. The main difference is that AppHangsV2 differentiates between fully-blocking and non-fully-blocking app hangs, which you might choose to ignore. A fully-blocking app hang is when the main thread is stuck completely, and the app can't render a single frame. A non-fully-blocking app hang is when the app appears stuck to the user, but can still render a few frames. Fully-blocking app hangs are more actionable because the stacktrace shows the exact blocking location on the main thread. Non-fully-blocking app hangs can have a stacktrace that doesn't highlight the exact blocking location, since the main thread isn't completely blocked.
142+
As of version 8.39.0-beta.1, you can enable AppHangsV2, which is available on iOS and tvOS. The main difference is that AppHangsV2 differentiates between fully-blocking and non-fully-blocking app hangs, which you might choose to ignore. A fully-blocking app hang is when the main thread is stuck completely, and the app can't render a single frame. A non-fully-blocking app hang is when the app appears stuck to the user, but can still render a few frames. Fully-blocking app hangs are more actionable because the stacktrace shows the exact blocking location on the main thread. Non-fully-blocking app hangs can have a stacktrace that doesn't highlight the exact blocking location, since the main thread isn't completely blocked.
143143

144144
To enable the feature:
145145

docs/platforms/apple/guides/ios/session-replay/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ options.experimental.sessionReplay.redactAllImages = false
9292

9393
## Error Linking
9494

95-
Errors that happen on the page while a replay is running will be linked to the replay, making it possible to jump between related issues and replays. However, it's **possible** that in some cases the error count reported on the **Replays Details** page won't match the actual errors that have been captured. That's because errors can be lost, and while this is uncommon, there are a few reasons why it could happen:
95+
Errors that happen while a replay is running will be linked to the replay, making it possible to jump between related issues and replays. However, it's **possible** that in some cases the error count reported on the **Replays Details** page won't match the actual errors that have been captured. That's because errors can be lost, and while this is uncommon, there are a few reasons why it could happen:
9696

9797
- The replay was rate-limited and couldn't be accepted.
9898
- The replay was deleted by a member of your org.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
title: Set Up Session Replay
3+
sidebar_order: 5500
4+
notSupported:
5+
description: "Learn how to enable the Mobile Session Replay Beta in your app."
6+
---
7+
8+
<Note>
9+
10+
Mobile support for Session Replay is in Beta. Features available in Beta are still work-in-progress and may have bugs. We recognize the irony.
11+
12+
If you have any questions, feedback or would like to report a bug, please open a [GitHub issue](https://github.com/getsentry/sentry-dart/issues/new?template=BUG_REPORT.yml) with a link to a relevant replay in Sentry if possible.
13+
14+
</Note>
15+
16+
[Session Replay](/product/explore/session-replay/) helps you get to the root cause of an error or latency issue faster by providing you with a reproduction of what was happening in the user's device before, during, and after the issue. You can rewind and replay your application's state and see key user interactions, like taps, swipes, network requests, and console entries, in a single UI.
17+
18+
By default, our Session Replay SDK masks all text content, images, and user input, giving you heightened confidence that no sensitive data will leave the device. To learn more, see [product docs](/product/explore/session-replay/).
19+
20+
## Pre-requisites
21+
22+
Make sure your Sentry Flutter SDK version is at least 8.9.0, which is required for Session Replay.
23+
You can update your `pubspec.yaml` to the matching version:
24+
25+
```yaml
26+
dependencies:
27+
sentry_flutter: ^8.9.0
28+
```
29+
30+
## Setup
31+
32+
To set up the integration, add the following to your Sentry initialization:
33+
34+
```dart
35+
await SentryFlutter.init(
36+
(options) {
37+
...
38+
options.experimental.replay.sessionSampleRate = 1.0;
39+
options.experimental.replay.onErrorSampleRate = 1.0;
40+
},
41+
appRunner: () => runApp(MyApp()),
42+
);
43+
```
44+
45+
## Verify
46+
47+
While you're testing, we recommend that you set <PlatformIdentifier name="replays-session-sample-rate" /> to `1.0`. This ensures that every user session will be sent to Sentry.
48+
49+
Once testing is complete, **we recommend lowering this value in production**. We still recommend keeping <PlatformIdentifier name="replays-on-error-sample-rate" /> set to `1.0`.
50+
51+
## Sampling
52+
53+
Sampling allows you to control how much of your website's traffic will result in a Session Replay. There are two sample rates you can adjust to get the replays relevant to you:
54+
55+
1. <PlatformIdentifier name="replays-session-sample-rate" /> - The sample rate for
56+
replays that begin recording immediately and last the entirety of a user's session.
57+
2. <PlatformIdentifier name="replays-on-error-sample-rate" /> - The sample rate for
58+
replays that are recorded when an error happens. This type of replay will record
59+
up to a minute of events prior to the error and continue recording until the session
60+
ends.
61+
62+
Sampling starts as soon as a session begins. The <PlatformIdentifier name="replays-session-sample-rate" /> is then evaluated. If the session is sampled, replay recording will start immediately. If not, <PlatformIdentifier name="replays-on-error-sample-rate" /> will be evaluated. If the session is sampled at this point, the replay will be buffered and will only be uploaded to Sentry if an error occurs.
63+
64+
## Privacy
65+
66+
The SDK is recording and aggressively redacting (masking) all text and images, according to the configuration in `options.experimental.replay`.
67+
You can tune this and add custom masking rules to fit your needs. For example, you can explicitly mask or unmask widgets by type,
68+
or you can even have a callback to decide whether a specific widget instance should be masked:
69+
70+
```dart
71+
options.experimental.replay.mask<IconButton>();
72+
options.experimental.replay.unmask<Image>();
73+
options.experimental.replay.maskCallback<Text>(
74+
(Element element, Text widget) =>
75+
(widget.data?.contains('secret') ?? false)
76+
? SentryMaskingDecision.mask
77+
: SentryMaskingDecision.continueProcessing);
78+
```
79+
80+
You can find more details in the documentation for each method.
81+
82+
<Note>
83+
84+
If you find that data isn't being redacted with the default settings, please let us know by creating a [GitHub issue](https://github.com/getsentry/sentry-dart/issues/new?template=BUG_REPORT.yml).
85+
86+
</Note>
87+
88+
To disable redaction altogether (not to be used on applications with sensitive data):
89+
90+
```dart
91+
options.experimental.replay.maskAllText = false;
92+
options.experimental.replay.maskAllImages = false;
93+
```
94+
95+
## Error Linking
96+
97+
Errors that happen while a replay is running will be linked to the replay, making it possible to jump between related issues and replays. However, it's **possible** that in some cases the error count reported on the **Replays Details** page won't match the actual errors that have been captured. That's because errors can be lost, and while this is uncommon, there are a few reasons why it could happen:
98+
99+
- The replay was rate-limited and couldn't be accepted.
100+
- The replay was deleted by a member of your org.
101+
- There were network errors and the replay wasn't saved.

0 commit comments

Comments
 (0)