diff --git a/cspell.json b/cspell.json
index 678585f..2cd046e 100644
--- a/cspell.json
+++ b/cspell.json
@@ -2,6 +2,16 @@
"version": "0.2",
"language": "en",
"words": [
+ "consteval",
+ "prebuild",
+ "destroot",
+ "rootproject",
+ "Slurper",
+ "libreactnative",
+ "libhermesvm",
+ "libc",
+ "hermesc",
+ "udpsocket",
"DCIM",
"backgrounding",
"debuggerd",
@@ -72,6 +82,8 @@
"androidx",
"Bugsee",
"bugsee",
+ "creditcard",
+ "cardnumber",
"symbolicate",
"symbolication",
"symbolicated",
@@ -231,6 +243,18 @@
"sandboxing",
"libil",
"unbreak",
- "Podspec"
+ "Podspec",
+ "javascriptcore",
+ "reactnative",
+ "slashy",
+ "avplayer",
+ "ABRT",
+ "SEGV",
+ "oslog",
+ "swipeable",
+ "collapsable",
+ "RGBA",
+ "RRGGBB",
+ "RRGGBBAA"
]
}
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 0e5843d..b1255d5 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -12,7 +12,7 @@ Using Bugsee on mobile devices requires installation of Bugsee lightweight SDK:
* [Installing iOS SDK](/sdk/ios/installation/)
* [Installing Android SDK](/sdk/android/installation/)
* [Installing Cordova SDK](/sdk/cordova/installation/)
-* [Installing React Native SDK](/sdk/react_native/installation/)
+* [Installing React Native SDK](/sdk/react_native/v6/installation/)
* [Installing Flutter SDK](/sdk/flutter/installation/)
* [Installing Unity SDK](/sdk/unity/installation/)
* [Installing KMP SDK (Beta)](/sdk/kmp/installation/)
@@ -111,7 +111,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
- View
+ View
View
@@ -133,7 +133,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
View
- View
+ View
View
View
View
@@ -144,7 +144,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
- View
+ View
View
View
View
@@ -155,7 +155,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
View
- View
+ View
View
View
View
@@ -166,7 +166,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
View
- View
+ View
View
View
View
@@ -177,7 +177,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
View
- View
+ View
View
View
View
@@ -188,7 +188,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
View
- View
+ View
View
View
View
@@ -199,7 +199,7 @@ Bugsee has a very rich feature set, yet on some platforms we managed to achieve
View
View
View
- View
+ View
View
View
View
diff --git a/docs/sdk/ios/release-notes.md b/docs/sdk/ios/release-notes.md
index b0ab2df..a93d5be 100644
--- a/docs/sdk/ios/release-notes.md
+++ b/docs/sdk/ios/release-notes.md
@@ -627,7 +627,7 @@ It is controlled by sanitizeNetworkData/BugseeSanitizeNetworkDataKey option (def
- Feature: Refactor logging capturing system to produce cleaner logs
- Feature: Better handling of multi-window hierarchies, lower cpu load.
- Feature: Auto-hide CC text fields in common payment libraries (Stripe, Braintree, card.io)
-- Feature: Add React native custom logger [read more](/sdk/react_native/logs/)
+- Feature: Add React native custom logger [read more](/sdk/react_native/v6/logs/)
- Bug fix: Incorrect addresses in C++ exceptions in some cases
diff --git a/docs/sdk/react_native/appearance.md b/docs/sdk/react_native/appearance.md
new file mode 100644
index 0000000..213cba8
--- /dev/null
+++ b/docs/sdk/react_native/appearance.md
@@ -0,0 +1,101 @@
+---
+title: "Appearance"
+description: "Customizing the colors of the Bugsee report dialog in React Native SDK 7.x with Bugsee.appearance: the color properties on each platform, reading them back, and errors."
+sidebar_position: 20
+slug: "/sdk/react_native/appearance"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+`Bugsee.appearance` sets the colors of the bug report dialog, so that it matches your app. It is one surface for both platforms: each property sets one color of the report dialog, on Android, on iOS, or on both.
+
+The colors of the feedback chat are set on the feedback package's own `appearance`; see [Feedback](/sdk/react_native/feedback#appearance).
+
+## Setting colors
+
+Assign a hex color string to a property:
+
+```ts
+import { Platform } from 'react-native';
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.appearance.backgroundColor = '#101828';
+Bugsee.appearance.textColor = '#ffffff';
+Bugsee.appearance.versionColor = '#98a2b3';
+
+if (Platform.OS === 'android') {
+ Bugsee.appearance.actionBarColor = '#1d2939';
+ Bugsee.appearance.actionBarTextColor = '#ffffff';
+} else {
+ Bugsee.appearance.navigationBarColor = '#1d2939';
+ Bugsee.appearance.cellBackgroundColor = '#1d2939';
+}
+```
+
+- Colors are CSS hex strings: `#RGB`, `#RGBA`, `#RRGGBB` or `#RRGGBBAA`, with alpha last. The `#` is optional, and `#RRGGBB` is opaque.
+- The color is applied during the assignment, synchronously.
+- Set the colors in your startup code, before a report dialog can open. You can set them before or after `Bugsee.launch`. Colors are kept in memory only, on both platforms, so set them at every app start.
+
+## Color properties
+
+Each property exists on Android, on iOS, or on both:
+
+| Property | Android | iOS |
+| --- | --- | --- |
+| `backgroundColor` | `ReportAppearance.BackgroundColor`: the dialog's background. | `reportBackgroundColor` |
+| `textColor` | `ReportAppearance.TextColor`: text and input text. | `reportTextColor`: label text. |
+| `versionColor` | `ReportAppearance.VersionColor`: the version label. | `reportVersionColor`: the version label. |
+| `actionBarColor` | `ReportAppearance.ActionBarColor`: the action bar's background. | |
+| `actionBarTextColor` | `ReportAppearance.ActionBarTextColor`: the action bar's button text. | |
+| `actionBarButtonBackgroundClickedColor` | `ReportAppearance.ActionBarButtonBackgroundClickedColor`: an action bar button's background while pressed. | |
+| `editTextBackgroundColor` | `ReportAppearance.EditTextBackgroundColor`: the input fields' background. | |
+| `hintColor` | `ReportAppearance.HintColor`: the input fields' hint text. | |
+| `severityLabelActiveColor` | `ReportAppearance.SeverityLabelActiveColor`: the selected severity label. | |
+| `cellBackgroundColor` | | `reportCellBackgroundColor`: the background of the table cells. |
+| `navigationBarColor` | | `reportNavigationBarColor` |
+| `placeholderColor` | | `reportPlaceholderColor`: the input fields' placeholder text. |
+| `sendButtonColor` | | `reportSendButtonColor`. **Not applied** in iOS SDK 7.0.0-beta7, whose report screen uses the system Done button. |
+| `closeButtonColor` | | `reportCloseButtonColor`. **Not applied** in iOS SDK 7.0.0-beta7, whose report screen uses the system Cancel button. |
+
+Check `Platform.OS` before setting a property that exists on one platform only: setting it on the other throws.
+
+The report dialog has more appearance settings than these colors. The field placeholder texts (`ReportAppearance.SummaryPlaceholder` and the others on Android, `reportSummaryPlaceholder` and the others on iOS), the title of the Android notification, and the iOS theme `style` are not available from JavaScript in this beta.
+
+## Reading colors
+
+Reading a property returns the color in effect, as a lowercase `#rrggbbaa` string, alpha last:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const background = Bugsee.appearance.backgroundColor; // for example '#101828ff', or undefined
+```
+
+| Platform | A color you have not set |
+| --- | --- |
+| Android | `undefined`: only the colors you set are stored. |
+| iOS | The iOS theme's default for that color. |
+
+Reading a property that does not exist on the running platform returns `undefined`.
+
+## Errors
+
+An assignment that is rejected throws, and changes nothing:
+
+| Assignment | Thrown |
+| --- | --- |
+| A value that is not a string | `TypeError` |
+| A string that is not a hex color | `RangeError` |
+| A property that does not exist on the running platform | `RangeError` |
+| A name that is not one of the properties above (a typo, for example) | `RangeError` |
+| A color that could not be applied | `Error` (`… was not applied`) |
+
+Error messages name the property, never the value you assigned.
+
+## Related pages
+
+- [Feedback](/sdk/react_native/feedback#appearance): the feedback chat's colors.
+- [Bug reporting](/sdk/react_native/manual/bug-reporting): the report dialog and its fields.
+- Native SDK reference: [Android appearance](/sdk/android/appearance#reportappearance) and [iOS appearance](/sdk/ios/appearance).
diff --git a/docs/sdk/react_native/breadcrumbs.mdx b/docs/sdk/react_native/breadcrumbs.mdx
new file mode 100644
index 0000000..9f2b1e2
--- /dev/null
+++ b/docs/sdk/react_native/breadcrumbs.mdx
@@ -0,0 +1,187 @@
+---
+title: "Breadcrumbs"
+description: "What breadcrumbs are in Bugsee React Native SDK 7.x, how to turn them on, record your own with Bugsee.addBreadcrumb, and rewrite or drop them with setBreadcrumbFilter."
+sidebar_position: 9
+slug: "/sdk/react_native/breadcrumbs"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Breadcrumbs are small entries that record the steps leading up to an issue: a screen opened, a checkout started, a setting changed. They are placed on the report timeline next to the video, logs and network events.
+
+## Turning breadcrumbs on
+
+Breadcrumb capture is **off by default**, on both platforms. Turn it on with the `captureBreadcrumbs` launch option:
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.captureBreadcrumbs = true;
+
+Bugsee.launch('', options);
+```
+
+| Option | Key | Default | Description |
+| --- | --- | --- | --- |
+| `captureBreadcrumbs` | `com.bugsee.option.capture.breadcrumbs` | `false` | Record breadcrumbs. While off, `Bugsee.addBreadcrumb` records nothing, and the filter is not offered any breadcrumb. |
+| (no accessor) | `com.bugsee.option.capture.breadcrumbs.extras` | `false` | Attach raw system data to the automatic breadcrumbs of system events. Android: the `Intent` extras of system broadcasts. iOS: the notification `userInfo` of device events. |
+
+See [Configuration](/sdk/react_native/configuration) for every option.
+
+## Where breadcrumbs come from
+
+- **Your own breadcrumbs**, recorded with [`Bugsee.addBreadcrumb`](#recording-breadcrumbs).
+- **Automatic breadcrumbs**, recorded in native code on both platforms. Your [filter](#filtering-breadcrumbs) sees these too.
+ - **Android**: app lifecycle, device orientation, keyboard events and system broadcasts, among others.
+ - **iOS**: app lifecycle (foreground and background), device orientation and memory warnings; screen changes of native view controllers; keyboard and text-field focus; connectivity changes; HTTP requests, with the built-in query-parameter redaction applied; taps and other gestures, while touch capture runs; blackouts; and device events such as protected-data availability, locale, time zone and clock changes, battery state and level, Low Power Mode and thermal state.
+
+The React Native package records no breadcrumbs from JavaScript on its own: there are no automatic navigation or touch breadcrumbs for React components. Add the ones you need with `addBreadcrumb`, for example from your navigation library's state-change listener.
+
+## Recording breadcrumbs
+
+`Bugsee.addBreadcrumb(crumb)` records one breadcrumb:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.addBreadcrumb({
+ category: 'navigation',
+ level: 'info',
+ message: 'Opened checkout',
+ type: 'default',
+ data: { cartSize: 3 },
+});
+```
+
+| Field | Type | Required | Description |
+| --- | --- | --- | --- |
+| `category` | `string` | Yes | A group for the breadcrumb, such as `navigation` or `ui`. |
+| `level` | `BreadcrumbLevel` | Yes | `debug`, `info`, `warning`, `error` or `fatal`. See [Levels](#levels). |
+| `message` | `string` | Yes | What happened. |
+| `type` | `string` | Yes | The kind of breadcrumb, such as `default` or `user`. |
+| `data` | plain object or `null` | No | Extra values. Leave it out, or pass `null`, for a breadcrumb without data. |
+
+The strings may be empty. The native SDK stamps the time when it records the breadcrumb; there is no timestamp field to pass.
+
+`data` accepts the same values as [event parameters](/sdk/react_native/events-and-traces#accepted-parameter-values): strings, finite numbers, booleans, `null`, and arrays and plain objects of those, nested up to 16 levels. It is checked and copied when you call `addBreadcrumb`, so changing your object afterward does not change the breadcrumb.
+
+`addBreadcrumb` returns nothing. Every breadcrumb goes through your [breadcrumb filter](#filtering-breadcrumbs) before it is recorded.
+
+On iOS the breadcrumb is recorded on the main thread, shortly after the call returns.
+
+### Invalid input
+
+`addBreadcrumb` throws synchronously, and records nothing, when:
+
+| Input | Thrown |
+| --- | --- |
+| `crumb` that is not a plain object (including `null`, an array or a class instance) | `TypeError` |
+| `category`, `message` or `type` that is not a string | `TypeError` |
+| `level` that is not one of the five names | `TypeError` |
+| `data` that is not a plain object or `null` | `TypeError` |
+| A value in `data` that is not accepted (a `Date`, a function, a cycle, and so on) | `TypeError` |
+| A non-finite number in `data`, a number of 263 or more in magnitude, or nesting deeper than 16 levels | `RangeError` |
+
+### When nothing is recorded
+
+`addBreadcrumb` does not throw when the SDK records nothing for reasons outside your input. It logs one of these lines (to logcat on Android, to the device log on iOS) and drops the breadcrumb:
+
+| Line | Cause |
+| --- | --- |
+| `addBreadcrumb dropped: capture is off or the SDK made no crumb` | `captureBreadcrumbs` is off, or the SDK could not create a breadcrumb, for example before `launch`. |
+| `addBreadcrumb dropped: its data is not a JSON object` | `data` could not be read as a JSON object. |
+
+## Levels
+
+The level is passed as a name, and each native SDK stores it on its own scale:
+
+| Name | Android | iOS |
+| --- | --- | --- |
+| `debug` | Debug | Debug |
+| `info` | Info | Info |
+| `warning` | Warning | Warning |
+| `error` | Error | Error |
+| `fatal` | Fatal | **Error**: the iOS scale has no fatal level. |
+
+On iOS, a `fatal` breadcrumb is therefore recorded, and read back by the filter, as `error`. An automatic breadcrumb recorded at the verbose level reaches the filter as `debug`.
+
+## Filtering breadcrumbs
+
+`Bugsee.setBreadcrumbFilter(callback)` installs a filter that sees each breadcrumb before it is recorded, yours and the native SDK's. Return the breadcrumb (changed or not) to keep it, or `null` to drop it:
+
+```ts
+import Bugsee, { type BreadcrumbSnapshot } from '@bugsee/react-native';
+
+Bugsee.setBreadcrumbFilter((crumb: BreadcrumbSnapshot) => {
+ // Drop UI breadcrumbs entirely
+ if (crumb.category === 'ui') {
+ return null;
+ }
+ // Remove e-mail addresses from the message
+ if (crumb.message !== undefined) {
+ return { ...crumb, message: crumb.message.replace(/\S+@\S+/g, '') };
+ }
+ return crumb;
+});
+```
+
+Install the filter **before** `Bugsee.launch`, at the top of your startup code. A breadcrumb filter set before `launch` stays in effect after it, on both platforms, and breadcrumbs recorded before the filter is installed are not filtered.
+
+There is one filter at a time. A later call replaces it, and `setBreadcrumbFilter()` or `setBreadcrumbFilter(null)` removes it, so breadcrumbs are recorded without one. A value that is not a function, `null` or `undefined` throws `TypeError` and leaves the previous filter in place.
+
+The callback is chosen when a breadcrumb arrives, with one exception for your own breadcrumbs: a breadcrumb you passed to `addBreadcrumb` while a filter was installed is answered by that filter, even if you clear or replace the filter on the same turn. A breadcrumb you meant to redact is not recorded unredacted because the filter changed right after you added it.
+
+### The breadcrumb the filter receives
+
+The callback gets a `BreadcrumbSnapshot`. A field the breadcrumb does not have is absent, which is why every field is optional:
+
+| Field | Type | Writable |
+| --- | --- | --- |
+| `category` | `string` | Yes |
+| `level` | `BreadcrumbLevel` | Yes |
+| `message` | `string` | Yes |
+| `type` | `string` | Yes |
+| `data` | object or `null` | Yes |
+| `timestamp` | `number` | No |
+
+### What a filter returns
+
+| Result | Effect |
+| --- | --- |
+| An object with the writable fields | Kept, with those fields set to what you returned. |
+| `null` or `undefined` | Dropped. |
+| A `Promise` | Waited on; its value is treated the same way. |
+| A non-object, an array or a function | Dropped. |
+| An object that leaves out a writable field the snapshot had | Dropped. |
+| The callback throws, or the promise rejects | Dropped. |
+
+A kept result must carry every writable field present in the snapshot (`category`, `level`, `message`, `type`, and `data` when the breadcrumb had data), as an own property and not `undefined`. Leaving one out drops the breadcrumb rather than keeping that field unredacted, so start from a spread of the snapshot, as in the example.
+
+The values must also be valid: the strings must be strings, `level` must be one of the five names, and `data` must be `null` (which clears the data) or a plain object of [accepted values](/sdk/react_native/events-and-traces#accepted-parameter-values). An invalid value drops the breadcrumb.
+
+This check also runs on `data` you return unchanged. A breadcrumb the native SDK recorded with data outside the accepted values (a number of 263 or more, for example) is dropped while a filter is installed, even if your filter returns it as it came.
+
+A field the snapshot did not have cannot be added back: it is ignored. `timestamp` is never written back, so you do not need to return it.
+
+### Async filters
+
+Your callback runs asynchronously, and it may return a promise. Capture does not wait for the answer.
+
+Neither platform sets a deadline for breadcrumbs, and the original breadcrumb is never recorded in place of an answer. A callback that never settles means the breadcrumb is not recorded; an answer that arrives late is still applied, and the breadcrumb is recorded then. Make sure your filter always settles: on Android, each unanswered breadcrumb also keeps holding memory for the rest of the session.
+
+### Reloads
+
+A filter is a function in the JavaScript runtime. When the runtime reloads (a development reload, for example), breadcrumbs still waiting for an answer are dropped.
+
+After the reload, **the filter stays on, but nothing in the new runtime answers it**, and neither platform has a deadline. Until your code calls `setBreadcrumbFilter` again, no breadcrumb is recorded, yours or the automatic ones. Call `setBreadcrumbFilter` early in your startup code, or `setBreadcrumbFilter(null)` if the new bundle has no filter.
+
+See [Privacy: Breadcrumbs](/sdk/react_native/privacy/breadcrumbs) for redaction guidance.
+
+## Related pages
+
+- [Privacy: Breadcrumbs](/sdk/react_native/privacy/breadcrumbs): redacting and dropping breadcrumbs.
+- [Custom events & traces](/sdk/react_native/events-and-traces): other signals on the same timeline.
+- [Configuration](/sdk/react_native/configuration): every launch option.
diff --git a/docs/sdk/react_native/configuration.mdx b/docs/sdk/react_native/configuration.mdx
index e9b8b58..c1ac95f 100644
--- a/docs/sdk/react_native/configuration.mdx
+++ b/docs/sdk/react_native/configuration.mdx
@@ -1,164 +1,370 @@
---
title: "Configuration"
-description: "Complete reference of Bugsee React Native launch options for iOS and Android, including recording, crash detection, network capture, and trigger settings."
-sidebar_position: 1
+description: "The launch options of Bugsee React Native SDK 7.x: the options object and its accessors, the shared com.bugsee.option.* keys, enums, the endpoint, and reading the effective options back."
+sidebar_position: 3
slug: "/sdk/react_native/configuration"
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-## Launching with options
-
-:::warning
-iOS/iPadOS: Since v6.0.0 the underlying Bugsee iOS SDK supports the simulator; crash capture is excluded. For full functionality, launch your app with Bugsee on a real device.
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
:::
-Bugsee behavior is very customizable, if default configuration is not satisfying your needs you can launch the SDK with additional parameters. Use instance of ```IOSLaunchOptions``` or ```AndroidLaunchOptions``` for corresponding platform to change Bugsee behavior.
+You configure the SDK with the options you pass to `Bugsee.launch` (and later `Bugsee.relaunch`). The same `com.bugsee.option.*` keys work on both platforms, so there is no per-platform key mapping: apart from the endpoint the Expo plugin can supply, the options you pass are the options the SDK applies, on both platforms. Enum-typed options take numbers; see [Enum reference](#enum-reference).
+## Two ways to pass options
-
-
+`launch` and `relaunch` accept either form, and both have the same effect:
-```javascript
-import Bugsee from 'react-native-bugsee';
+- **The options object**, from `createDefaultLaunchOptions()`, with typed accessors. Pass it as is; there is no serialize step to call.
+- **A plain map** of `com.bugsee.option.*` keys, for options you build or merge yourself.
-// ...
+
+
-export default class App extends Component<{}> {
- constructor(props) {
- super(props);
+```ts
+import Bugsee, { createDefaultLaunchOptions, LogLevel } from '@bugsee/react-native';
- const bugseeOptions = new Bugsee.IOSLaunchOptions();
+const options = createDefaultLaunchOptions();
+options.duration = 120;
+options.captureLogsLevel = LogLevel.Info;
+options.wifiOnlyUpload = true;
- bugseeOptions.shakeToReport = true;
- bugseeOptions.reportPrioritySelector = true;
- bugseeOptions.defaultBugPriority = Bugsee.BugseeSeverityLevel.Critical;
+Bugsee.launch(token, options);
+```
- Bugsee.launch("", bugseeOptions);
- }
-}
+
+
+
+```ts
+import Bugsee, { LogLevel } from '@bugsee/react-native';
+
+Bugsee.launch(token, {
+ 'com.bugsee.option.config.duration': 120,
+ 'com.bugsee.option.capture.logs.level': LogLevel.Info,
+ 'com.bugsee.option.config.wifi-only-upload': true,
+});
```
-
+
+
+`BugseeLaunchOptions.serialize(options)` returns the plain map an options object stands for, as a snapshot: a later change to the object does not change a map you already took.
-```javascript
-import Bugsee from 'react-native-bugsee';
+## The options object
-// ...
+`createDefaultLaunchOptions()` returns an empty options object for the running platform: an `IOSLaunchOptions` on iOS, an `AndroidLaunchOptions` on Android. Pass a platform (`'ios'` or `'android'`) to get the other one; any other platform throws.
-export default class App extends Component<{}> {
- constructor(props) {
- super(props);
+The object is **not** pre-filled with defaults. An option you leave unset is not sent at all, so the native SDK applies its own default. Setting an accessor to `undefined` removes the key again, rather than sending an empty value that would override the default.
- const bugseeOptions = new Bugsee.AndroidLaunchOptions();
+Accessors shared by both platforms live on the base class, `BugseeLaunchOptions`. Platform-only accessors live on `AndroidLaunchOptions` and `IOSLaunchOptions`, so an iOS-only option cannot be set on an Android options object by accident. To reach one, narrow the object first:
- bugseeOptions.shakeToTrigger = true;
- bugseeOptions.notificationBarTrigger = false;
+```ts
+import {
+ AndroidLaunchOptions,
+ IOSLaunchOptions,
+ createDefaultLaunchOptions,
+} from '@bugsee/react-native';
- Bugsee.launch("", bugseeOptions);
- }
+const options = createDefaultLaunchOptions();
+if (options instanceof AndroidLaunchOptions) {
+ options.triggerByNotification = false;
+} else if (options instanceof IOSLaunchOptions) {
+ options.captureDiskSpace = true;
}
```
-
-
+### Any key: `setCustomOption`
-Note that when you launch Bugsee, it starts working in background with the specified launch options. Later, if you change launch options and reload JS layer, they will be ignored as Bugsee is already running. So, to workaround this, you should either relaunch the whole app or call Bugsee.relaunch() with the new launch options.
-
-
-### Available Options
-
-#### For iOS
-
-|Key|Default|Notes
-|---|---|---|
-|captureDeviceAndNetworkNames|false|Capture device name, wifi SSID and mobile carrier name.|
-|captureLogs|true|Automatically capture all console logs|
-|crashReport|true|Catch and report application crashes (\*)|
-|defaultBugPriority|High|Default priority for bugs|
-|defaultCrashPriority|Blocker|Default priority for crashes|
-|killDetection|false|Detect abnormal termination (experimental, [read more](/sdk/ios/app-kills/))|
-|maxRecordingTime|60|Maximum recording duration|
-|monitorNetwork|true|Capture network traffic|
-|reportPrioritySelector|false|Allow user to modify priority when reporting manually|
-|screenshotToReport|true|Screenshot key to trigger report|
-|shakeToReport|false|Shake gesture to trigger report|
-|style|Default|Enumeration of Default, Dark and BasedOnStatusBar
-|videoEnabled|true|Enable video recording|
-|frameRate|High|Specifies how often frames are captured|
-|screenshotEnabled|true|Attach screenshot to a report|
-|wifiOnlyUpload|false|Upload reports only when a device is connected to a WiFi network|
-|maxDataSize|50|Bugsee will avoid using more disk space than specified (in MB). If total Bugsee data size exceeds specified value, oldest recordings (even not sent) will be removed. Value should not be smaller than 10|
-
-:::warning
-* iOS allows only one crash detector to be active at a time, if you insist on using an alternative solution for handling crashes, you might want to use this option and disable Bugsee from taking over.
-:::
+`setCustomOption(key, value)` sets any option by its real `com.bugsee.option.*` key, whether or not it has an accessor. A custom key and an accessor write to the same map, so an option that has no accessor yet, including one added in a later 7.x native release, is reachable without a new release of this package. `undefined` removes the key, as with an accessor.
+```ts
+options.setCustomOption('com.bugsee.option.detect.http-errors', true);
+options.setCustomOption('com.bugsee.option.capture.network.body-size-limit', 10240);
+```
-#### For Android
+## Shared accessors
+
+These accessors exist on both platforms.
+
+| Accessor | Key | Type | Default | Description |
+| --- | --- | --- | --- | --- |
+| `duration` | `com.bugsee.option.config.duration` | number (seconds) | `60` | Length of the rolling capture buffer (video, logs, breadcrumbs). |
+| `wifiOnlyUpload` | `com.bugsee.option.config.wifi-only-upload` | boolean | `false` | Defer report uploads until the device is on Wi-Fi. |
+| `maxDataSize` | `com.bugsee.option.config.max-data-size` | number (MB) | `150` (Android) / `50` (iOS) | Disk space that reports waiting to be sent may take. Enforced on Android. On iOS this beta accepts the key but does not enforce it. See [Automatic retention](/sdk/react_native/privacy/cleanup#automatic-retention). |
+| `captureVideo` | `com.bugsee.option.capture.video` | boolean | `true` | Record the screen for reports. |
+| `captureNetwork` | `com.bugsee.option.capture.network` | boolean | `true` | Record network requests and responses. |
+| `captureLogs` | `com.bugsee.option.capture.logs` | boolean | `true` | Capture logs automatically, including `console.*` output. `false` stops console forwarding; lines you send with `Bugsee.log` are still recorded. |
+| `captureLogsLevel` | `com.bugsee.option.capture.logs.level` | `LogLevel` | `Verbose` | The most verbose level captured; less severe lines are dropped. `LogLevel.Info` keeps `Error`, `Warning` and `Info`. |
+| `captureBreadcrumbs` | `com.bugsee.option.capture.breadcrumbs` | boolean | `false` | Record breadcrumbs. While off, `Bugsee.addBreadcrumb` records nothing, on both platforms. |
+| `detectAndReportCrash` | `com.bugsee.option.detect.crash` | boolean | `true` | Report crashes. `false` also turns off the reporting of uncaught JavaScript errors, unhandled promise rejections and uncaught render errors. See [Turning automatic reporting off](/sdk/react_native/manual/crash-error-reporting#turning-automatic-reporting-off). |
+| `detectAndReportHang` | `com.bugsee.option.detect.hang` | boolean | `false` | Report when the main thread is blocked long enough to count as a hang. |
+
+The **Default** column applies to both platforms unless the row gives one per platform. Read the values in effect with [`getLaunchOptions()`](#reading-the-effective-options).
+
+## Android accessors
+
+`AndroidLaunchOptions` adds these.
+
+| Accessor | Key | Type | Default | Description |
+| --- | --- | --- | --- | --- |
+| `endpoint` | `com.bugsee.option.$$ENDPOINT` | string | production | API endpoint override; see [Endpoint](#endpoint). |
+| `videoMode` | `com.bugsee.option.capture.video.mode` | `VideoMode` | `V2` | Screen-capture strategy. |
+| `logsUseAllSources` | `com.bugsee.option.capture.logs.allsources` | boolean | `false` | Read all logcat buffers instead of the default sources. |
+| `detectAndReportExitLowMemory` | `com.bugsee.option.detect.exit.low_memory` | boolean | `true` | Report exits where the OS killed the app to reclaim memory. |
+| `detectAndReportExitLowMemoryBackgroundAsError` | `com.bugsee.option.detect.exit.bg_low_memory_as_error` | boolean | `false` | Report a low-memory kill of a process that was not in the foreground as a non-fatal error rather than a crash. Applies only while `detectAndReportExitLowMemory` is on. |
+| `maxPendingReports` | `com.bugsee.option.config.max-pending-reports` | number | `30` | Most reports kept waiting to be sent. |
+| `maxPendingReportAge` | `com.bugsee.option.config.max-pending-report-age` | number (days) | `30` | Oldest a report waiting to be sent may get; `0` or less keeps reports until they are sent or evicted. |
+| `triggerByNotification` | `com.bugsee.option.reporting.triggers.notification-bar` | boolean | `true` | Show a notification-bar entry that opens the report UI. |
+
+The other Android-only keys are reachable with `setCustomOption`: see [Platform-only keys](#platform-only-keys).
+
+## iOS accessors
+
+`IOSLaunchOptions` adds these.
+
+| Accessor | Key | Type | Default | Description |
+| --- | --- | --- | --- | --- |
+| `endpoint` | `endpoint` | string | production | API endpoint override; see [Endpoint](#endpoint). Not a `com.bugsee.option.*` key on iOS. |
+| `captureAVPlayer` | `com.bugsee.option.capture.avplayer` | boolean | `false` | Capture video that plays through `AVPlayerLayer` and `AVPlayerViewController` in the recording. |
+| `captureDiskSpace` | `com.bugsee.option.capture.disk-space` | boolean | `false` | Monitor available disk space and include it in reports as a system trace and device properties. |
+| `crashHandlerType` | `com.bugsee.option.capture.crash-handler-type` | `CrashHandlerType` | `MachAndBSD` | How the crash reporter intercepts crashes. |
+| `crashSignals` | `com.bugsee.option.capture.crash-signals` | number (bit set) | every signal | The fatal signals the crash reporter intercepts: `ABRT` 1, `SEGV` 2, `BUS` 4, `ILL` 8, `FPE` 16, `TRAP` 32. Add the values to combine them. |
+
+## Other shared keys
+
+These keys are accepted by both native SDKs but have no accessor. Set them with `setCustomOption`, or in a plain map. Type and default are the same on both platforms, except where a row gives one per platform.
+
+### Detection
+
+| Key | Type | Default | Description |
+| --- | --- | --- | --- |
+| `com.bugsee.option.detect.early-crash` | boolean | `true` | Also catch crashes very early in startup. |
+| `com.bugsee.option.detect.exit` | boolean | `true` | Detect and report application exits. |
+| `com.bugsee.option.detect.hang.level.fair` | number (ms) | `3000` | Main-thread block that counts as a "Fair" hang. |
+| `com.bugsee.option.detect.hang.level.medium` | number (ms) | `5000` | Main-thread block that counts as a "Medium" hang. |
+| `com.bugsee.option.detect.hang.level.severe` | number (ms) | `10000` | Main-thread block that counts as a "Severe" hang. |
+| `com.bugsee.option.detect.http-errors` | boolean | `false` | Turn HTTP 5xx responses into error reports. |
+| `com.bugsee.option.detect.main_thread_misuse` | boolean | `false` | Report file, network or database work done on the main thread. |
+| `com.bugsee.option.detect.anomaly` | boolean | `false` | The statistical performance-anomaly detector. |
+| `com.bugsee.option.detect.frustration` | boolean | `false` | Detect user-frustration patterns such as rage taps and report them. |
+
+### Capture
+
+| Key | Type | Default | Description |
+| --- | --- | --- | --- |
+| `com.bugsee.option.capture.screenshot` | boolean | `true` | Take a screenshot when a report is created. |
+| `com.bugsee.option.capture.screenshot.scale` | number | `1` | Down-then-up scaling of the screenshot, which destroys fine detail; `1` turns it off. |
+| `com.bugsee.option.capture.view-hierarchy` | boolean | `true` | Capture the view hierarchy for reports (also needs [`Bugsee.wrap`](/sdk/react_native/installation#4-launch-bugsee)). |
+| `com.bugsee.option.capture.breadcrumbs.extras` | boolean | `false` | Attach raw system data to the breadcrumbs the native SDK records for system events: the `Intent` extras of system broadcasts on Android, the notification `userInfo` of device events on iOS. |
+| `com.bugsee.option.capture.video.quality` | `VideoQuality` | `Default` | Quality of the encoded video. |
+| `com.bugsee.option.capture.video.frame-rate` | `FrameRate` | `High` | How often frames are captured. |
+| `com.bugsee.option.capture.video.scale` | number | `1` | Extra down-scaling of the recorded video, for example `0.5`. |
+| `com.bugsee.option.capture.video.adaptive` | boolean | `false` (Android) / `true` (iOS) | Skip frames while nothing on screen has been redrawn. |
+| `com.bugsee.option.capture.network.on-launch` | boolean | `false` | Start network capture during `launch` instead of when capture starts, so startup requests are not missed. |
+| `com.bugsee.option.capture.network.body-size-limit` | number (bytes) | `20480` | Largest request or response body captured. |
+| `com.bugsee.option.capture.network.body-without-type` | boolean | `false` | Also keep bodies that declare no content type. |
+| `com.bugsee.option.capture.network.default-sanitizer` | boolean | `true` | Redact known sensitive keys in URLs, headers and JSON bodies. See [Privacy: Network](/sdk/react_native/privacy/network) for how it combines with a network filter on each platform. |
+
+### Reporting
+
+| Key | Type | Default | Description |
+| --- | --- | --- | --- |
+| `com.bugsee.option.reporting.triggers.shake` | boolean | `true` | Open the report UI when the device is shaken. |
+| `com.bugsee.option.reporting.triggers.screenshot` | boolean | `false` | Open the report UI when the user takes a screenshot. |
+| `com.bugsee.option.reporting.defaults.crash-priority` | `IssueSeverity` | `Blocker` | Severity of crash reports. |
+| `com.bugsee.option.reporting.defaults.error-priority` | `IssueSeverity` | `High` | Severity of error reports. |
+| `com.bugsee.option.reporting.defaults.bug-priority` | `IssueSeverity` | `High` | Severity of bug reports. |
+| `com.bugsee.option.reporting.ui.summary-required` | boolean | `false` | Make the Summary field mandatory. |
+| `com.bugsee.option.reporting.ui.description-required` | boolean | `false` | Make the Description field mandatory. |
+| `com.bugsee.option.reporting.ui.email-required` | boolean | `false` | Make the Email field mandatory. |
+| `com.bugsee.option.reporting.ui.labels-enabled` | boolean | `false` | Show the Labels field. |
+| `com.bugsee.option.reporting.ui.labels-required` | boolean | `false` | Make the Labels field mandatory. |
+| `com.bugsee.option.reporting.ui.priority-selector-enabled` | boolean | `false` | Let the user pick the priority. |
+
+### Upload and performance
+
+| Key | Type | Default | Description |
+| --- | --- | --- | --- |
+| `com.bugsee.option.config.notify-flush-delay` | number (ms) | `0` | Coalescing window before queued `Bugsee.notify` items are sent. |
+| `com.bugsee.option.performance.enabled` | boolean | `true` | Master switch for performance monitoring; see [Performance monitoring](/sdk/react_native/performance). |
+| `com.bugsee.option.performance.sample-rate` | number `[0, 1]` | `0.01` | Probability that a transaction is sampled for a standalone upload, which is not active in this beta; see [Sampling](/sdk/react_native/performance#sampling). |
+| `com.bugsee.option.performance.adaptive-sampling` | boolean | `true` | Promote unsampled transactions that look interesting into the standalone upload, which is not active in this beta. |
+
+## Platform-only keys
+
+Keys for native WebView capture, shared or platform-only, are omitted from this page and from the shared tables above.
+
+Some keys are accepted by one SDK only; the other SDK does not recognize them. `setCustomOption` does not check the platform, so set these only on the platform they belong to.
+
+**Android only.** Native SDK reference: [Android configuration](/sdk/android/configuration).
+
+| Key | Type | Default | Description |
+| --- | --- | --- | --- |
+| `com.bugsee.option.capture.respect-flag-secure` | boolean | `true` | Protect windows that set `FLAG_SECURE`: they are blanked in the video and screenshots and left out of the view hierarchy. See [Privacy: Video](/sdk/react_native/privacy/video). |
+| `com.bugsee.option.capture.video.custom-muxer` | boolean | `false` | Encode the video with Bugsee's own MP4 muxer instead of the system one. |
+| `com.bugsee.option.capture.video.fullscreen-keep-running` | boolean | `true` | With `VideoMode.Fullscreen`, keep screen capture running in the background, rather than stopping it and asking the user again on return. |
+| `com.bugsee.option.capture.video.fullscreen-remember-decision` | boolean | `true` | With `VideoMode.Fullscreen`, remember the user's screen-capture consent across launches. |
+| `com.bugsee.option.capture.video.secure-scrolling` | boolean | `false` | With `VideoMode.V1`, skip more frames while secure views are on screen. |
+| `com.bugsee.option.config.report-handler-callback-timeout` | number (seconds) | `30` | Lowers the report handler deadline; see [Report handler](/sdk/react_native/report-handler#async-callbacks-and-deadlines). |
+| `com.bugsee.option.config.report-processing-in-process` | boolean | `true` | Assemble and upload reports in the app's process. `false` schedules them as system jobs, which survive the process at the cost of upload latency. |
+| `com.bugsee.option.detect.anr.sampling` | boolean | `true` | Sample the main thread during an ANR, to attribute the report to the frames that were blocking. |
+| `com.bugsee.option.detect.hang.sampling` | boolean | `true` | The same for hangs, while `detectAndReportHang` is on. |
+| `com.bugsee.option.detect.exit.not_responding` | boolean | `true` | Report exits after the app stopped responding (ANR). |
+| `com.bugsee.option.detect.exit.not_responding.as_crash` | boolean | `false` | Report those exits as crashes rather than errors. |
+| `com.bugsee.option.detect.exit.*`: `dependency_died`, `excessive_resource_usage`, `other`, `package_state_changed`, `package_updated`, `permission_changed`, `unknown`, `user_requested`, `user_was_stopped` | boolean | `false` | Report exits for that reason too. |
+| `com.bugsee.option.performance.upload-mode` | string | `"batched"` | How a standalone performance upload would send data; that upload is not active in this beta. |
+| `com.bugsee.option.reporting.triggers.broadcast` | boolean | `false` | Let a broadcast intent open the report dialog. |
+
+**iOS only**, beyond the accessors above. Native SDK reference: [iOS configuration](/sdk/ios/configuration#available-options), which lists the options under their 6.x names, and the [iOS 7.x migration guide](/sdk/ios/v7/migration#2-option-keys), which maps them to these keys.
+
+| Key | Type | Default | Description |
+| --- | --- | --- | --- |
+| `com.bugsee.option.capture.bluetooth-status` | boolean | `false` | Monitor the Bluetooth state. Needs `NSBluetoothAlwaysUsageDescription` in `Info.plist`. |
+| `com.bugsee.option.capture.camera-preview` | boolean | `false` | Record the live camera image shown in an `AVCaptureVideoPreviewLayer`. This records whatever the camera sees, and adds work to your camera session. Off, a camera preview records as an empty rectangle. |
+| `com.bugsee.option.capture.device-network-names` | boolean | `false` | Capture the device name, the Wi-Fi network name and the mobile carrier name. |
+| `com.bugsee.option.capture.logs.oslog` | boolean | `false` | Accepted and ignored in this beta: `os_log` entries are not captured. |
+| `com.bugsee.option.capture.on-device-symbolication` | boolean | `false` | Symbolicate crash stack frames on the device. |
+| `com.bugsee.option.capture.sample-buffer-display-layer` | boolean | `false` | Capture video shown through an `AVSampleBufferDisplayLayer` in the recording (pixel-buffer samples only). |
+| `com.bugsee.option.capture.status-bar-info` | boolean | `false` | On-screen status indicators for testing the SDK itself. No effect in release builds of the SDK. |
+| `com.bugsee.option.capture.video.max-frame-rate` | number (fps) | `0` | Highest capture frame rate. `0` uses the rate `capture.video.frame-rate` picks. |
+| `com.bugsee.option.capture.video.min-frame-rate` | number (fps) | `0` | Lowest capture frame rate. `0` uses the rate `capture.video.frame-rate` picks. |
+| `com.bugsee.option.capture.video.privacy-blur` | boolean | `true` | Blur the frames of a screen transition instead of leaving them out. `false` freezes the video for the transition. |
+| `com.bugsee.option.capture.websocket` | boolean | `true` | Record WebSocket traffic; see [Network events](/sdk/react_native/network#websocket-traffic). |
+| `com.bugsee.option.config.build-target` | string | none | Build target name, sent with reports. |
+| `com.bugsee.option.config.build-type` | string | none | Build type, such as `debug` or `release`, sent with reports. |
+| `com.bugsee.option.config.data-encryption` | number | `0` | Encryption of the collected data: `0` none, `1` on device (keys kept in the Secure Enclave), `2` end to end (decrypted only on the server, so some features, such as the video preview, are missing). The package exports no constants for it. |
+| `com.bugsee.option.detect.crash.fill_empty_exception_stacks` | boolean | `false` | Fill in the stack of an uncaught `NSException` that has none from the crashing thread. This can change how crashes are grouped. |
+| `com.bugsee.option.detect.crash.swift_async_stacktraces` | boolean | `true` | Stitch Swift async frames into the stacks of C++ exceptions. |
+| `com.bugsee.option.reporting.ui.style` | number | `3` | Style of the report UI: `0` Light, `1` Dusk, `2` based on the status bar, `3` the system style. The package exports no constants for it. |
+
+## Enum reference
+
+Enum-typed options take a number. Use the exported constants rather than writing numbers: the values are each enum's internal value in the native SDKs, not its position in the list, so `LogLevel.Error` is `1` and `VideoMode.Fullscreen` is `20`.
+
+```ts
+import { FrameRate, IssueSeverity, VideoQuality } from '@bugsee/react-native';
+
+options.setCustomOption('com.bugsee.option.capture.video.frame-rate', FrameRate.Medium);
+options.setCustomOption('com.bugsee.option.capture.video.quality', VideoQuality.High);
+options.setCustomOption('com.bugsee.option.reporting.defaults.bug-priority', IssueSeverity.Critical);
+```
-|Key|Default|Notes
-|---|---|---|
-|captureDeviceAndNetworkNames|true|Capture device name, wifi SSID and mobile carrier name.|
-|captureLogs|true|Automatically capture all console logs|
-|crashReport|true|Catch and report application crashes|
-|defaultBugPriority|High|Default priority for bugs|
-|defaultCrashPriority|Blocker|Default priority for crashes|
-|frameRate|High|Specifies how often frames are captured|
-|handleAnr|false|Detect ANR (Application Not Responding) and transform it to a meaningful exception|
-|logLevel|Verbose|Minimal log level of Logcat messages, which will be attached to report|
-|maxDataSize|50|Maximum disk space consumed by Bugsee|
-|maxRecordingTime|60|Maximum recording duration|
-|monitorNetwork|true|Capture network traffic|
-|notificationBarTrigger|true|Trigger report from notification bar|
-|screenshotToReport|false|Trigger bug report by taking screenshot on device. Bugsee React Native SDK 5.4.0 and up. This feature requires additional permissions: **Android 14+**: DETECT_SCREEN_CAPTURE permission is required. More details about the permission and the native API involved in [Android development documentation](https://developer.android.com/about/versions/14/features/screenshot-detection). **Android 13**: READ_MEDIA_IMAGES permission is required. **Android 12** and below: READ_EXTERNAL_STORAGE permission is required. On Android 13 and below, Bugsee SDK monitors the gallery to detect screenshot creation and that's why the permissions mentioned above are required.|
-|reportPrioritySelector|false|Allow user to modify priority when reporting manually|
-|screenshotEnabled|true|Attach screenshot to a report|
-|serviceMode|false|Used, when Bugsee is launched from service. No video and no visual controls available. Recording continues even in background.|
-|shakeToTrigger|false|Shake gesture to trigger report|
-|videoEnabled|true|Enable video recording|
-|videoMode|VideoMode.V3|Specifies video recording mode. Available options are: VideoMode.V1, VideoMode.V2, VideoMode.V3|
-|wifiOnlyUpload|false|Upload reports only when a device is connected to a WiFi network|
+| Enum | Values | Used by |
+| --- | --- | --- |
+| `LogLevel` | `Error` 1, `Warning` 2, `Info` 3, `Debug` 4, `Verbose` 5 | `captureLogsLevel`, `Bugsee.log` |
+| `VideoMode` | `None` 0, `V1` 1, `V2` 2, `Fullscreen` 20, `DirectBuffers` 21 | `videoMode` (Android) |
+| `VideoQuality` | `Default` 0, `Medium` 1, `High` 2 | `capture.video.quality` |
+| `FrameRate` | `Low` 1, `Medium` 2, `High` 3 | `capture.video.frame-rate` |
+| `IssueSeverity` | `VeryLow` 1, `Medium` 2, `High` 3, `Critical` 4, `Blocker` 5 | `reporting.defaults.*-priority`, report severities |
+| `CrashHandlerType` | `BSD` 1, `Mach` 2, `MachAndBSD` 3 | `crashHandlerType` (iOS) |
+- `FrameRate` has no `Raw`: only Android has that rate, and the same number would mean different capture rates on the two platforms.
+- `CrashHandlerType` is iOS only. `BSD` uses BSD signal handlers. `Mach` uses a Mach exception handler plus a BSD handler for `SIGABRT`; other signals raised by software (`raise()`, `kill()`) are not reported. `MachAndBSD`, the default, uses both, so hardware faults and signals raised by software are reported.
-## Stop, Relaunch
-It is also possible to relaunch Bugsee with other options later
+A number that names no value of the enum is handled differently on each platform. Android: it is dropped (as is a number that is not whole), so the option keeps its default. iOS: it is not checked, and is applied as given. Use the exported constants.
+## Value types
-
-
+Option values are booleans, numbers and strings. Other values are dropped without an error. Android: any value that is not one of those three types (an array, an object or `null`). iOS: a value whose type does not fit its key (a string for a boolean key, say). The option then keeps its default.
-```javascript
-// Relaunch with other options.
-const options = new Bugsee.IOSLaunchOptions();
+## Endpoint
-// Set other launch options
-//...
+The endpoint override is the one option whose key differs per platform, which is why `endpoint` is an accessor on `AndroidLaunchOptions` and `IOSLaunchOptions` rather than on the base class. Set it on the object returned by `createDefaultLaunchOptions()` and the right key is written:
-Bugsee.relaunch(options);
+```ts
+const options = createDefaultLaunchOptions();
+options.endpoint = 'https://bugsee.example.com';
```
-
-
+| Platform | Key | What is sent |
+| --- | --- | --- |
+| Android | `com.bugsee.option.$$ENDPOINT` | The value, trimmed. Accepted with or without `/v2`. |
+| iOS | `endpoint` | The value, trimmed, without trailing slashes, with `/v2` added unless it already ends in `/v2`. |
-```javascript
-// Relaunch with other options.
-const options = new Bugsee.AndroidLaunchOptions();
+The `endpoint` getter returns what will be sent, so on iOS it reads back with `/v2`. An empty or blank value removes the override.
-// Set other launch options
-//...
+For a plain map, `endpointFor(platform, endpoint)` returns the entry to merge in, or `{}` for an empty value:
-Bugsee.relaunch(options);
+```ts
+import { Platform } from 'react-native';
+import Bugsee, { endpointFor } from '@bugsee/react-native';
+
+Bugsee.launch(token, {
+ 'com.bugsee.option.config.duration': 60,
+ ...endpointFor(Platform.OS === 'ios' ? 'ios' : 'android', 'https://bugsee.example.com'),
+});
```
-
-
+An Expo app can set the endpoint once in the [config plugin](/sdk/react_native/expo#custom-endpoint) instead. `launch` and `relaunch` then use it whenever their options carry no endpoint; an endpoint you pass yourself wins.
+
+## Reading the effective options
+
+`Bugsee.getLaunchOptions()` resolves to the options the native SDK reports as in effect, as a plain `com.bugsee.option.*` map, including the SDK's defaults for what you did not set:
+
+```ts
+async function logDuration() {
+ const effective = await Bugsee.getLaunchOptions();
+ console.log(effective['com.bugsee.option.config.duration']);
+}
+```
+
+Both platforms answer before launch too, with the defaults.
+
+An options object's getters return what you set on it, and nothing else, until you load the reported options into it. `BugseeLaunchOptions.refreshFrom(options, reported)` installs them; each call replaces the previous report. Getters then answer with the value you set, or failing that the reported one. Reported values are never sent back when the object is passed to `launch` or `relaunch`.
+
+```ts
+import Bugsee, { BugseeLaunchOptions, createDefaultLaunchOptions } from '@bugsee/react-native';
+
+async function effectiveDuration() {
+ const options = createDefaultLaunchOptions();
+ BugseeLaunchOptions.refreshFrom(options, await Bugsee.getLaunchOptions());
+ return options.duration; // the duration in effect
+}
+```
+
+## Changing options at runtime
+
+Options apply when the SDK launches. To change them later, pass a new set to `Bugsee.relaunch(options)`, which restarts the session; see [Lifecycle & status](/sdk/react_native/lifecycle).
+
+## Worked example
+
+```ts
+import { Platform } from 'react-native';
+import Bugsee, {
+ AndroidLaunchOptions,
+ CrashHandlerType,
+ IOSLaunchOptions,
+ IssueSeverity,
+ LogLevel,
+ createDefaultLaunchOptions,
+} from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.duration = 90;
+options.captureBreadcrumbs = true;
+options.captureLogsLevel = LogLevel.Info;
+options.detectAndReportHang = true;
+options.setCustomOption('com.bugsee.option.reporting.triggers.shake', false);
+options.setCustomOption('com.bugsee.option.reporting.defaults.bug-priority', IssueSeverity.Medium);
+
+if (options instanceof AndroidLaunchOptions) {
+ options.triggerByNotification = false;
+} else if (options instanceof IOSLaunchOptions) {
+ options.crashHandlerType = CrashHandlerType.MachAndBSD;
+}
+
+Bugsee.launch(
+ Platform.OS === 'ios' ? '' : '',
+ options,
+);
+```
-or stop the events and video recording.
+## Related pages
-```javascript
-// Stop recording completely
-Bugsee.stop()
-```
\ No newline at end of file
+- [Installation](/sdk/react_native/installation): launching the SDK.
+- [Lifecycle & status](/sdk/react_native/lifecycle): `relaunch` with new options.
+- [Privacy](/sdk/react_native/privacy/overview): masking and filters.
+- Native SDK reference: [Android configuration](/sdk/android/configuration) and [iOS configuration](/sdk/ios/configuration#available-options) (6.x option names; the [iOS 7.x migration guide](/sdk/ios/v7/migration#2-option-keys) maps them to the 7.x keys).
diff --git a/docs/sdk/react_native/error-boundary.mdx b/docs/sdk/react_native/error-boundary.mdx
new file mode 100644
index 0000000..cdc6b99
--- /dev/null
+++ b/docs/sdk/react_native/error-boundary.mdx
@@ -0,0 +1,146 @@
+---
+title: "Error boundary"
+description: "Catch render errors in a React component tree with the ErrorBoundary component of Bugsee React Native SDK 7.x, report them to Bugsee, and render a fallback."
+sidebar_position: 5
+slug: "/sdk/react_native/error-boundary"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+`` is a React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) that reports what it catches to Bugsee. When a component below it throws while rendering, it reports the error as a handled **error** report, with the React component stack, and renders a fallback in place of the broken tree.
+
+Use it around parts of your app that can fail on their own (a screen, a widget, a list item) so the rest of the app keeps working. Errors that no boundary catches are still reported, as crashes, when your root component is wrapped in `Bugsee.wrap`; see [Render errors](/sdk/react_native/manual/crash-error-reporting#render-errors).
+
+```tsx
+import { Text } from 'react-native';
+import { ErrorBoundary } from '@bugsee/react-native';
+
+export function CartScreen() {
+ return (
+ The cart could not be shown.}>
+
+
+ );
+}
+```
+
+`ErrorBoundary` is a named export of `@bugsee/react-native`. It is not a property of the default `Bugsee` export, as it was in 6.x.
+
+## Props
+
+| Prop | Type | Description |
+| --- | --- | --- |
+| `children` | `ReactNode` | The tree to guard. |
+| `fallback` | `ReactElement` or `(props: ErrorBoundaryFallbackProps) => ReactNode` | What to render after an error. Without it, the boundary renders nothing. |
+| `onError` | `(error: unknown, componentStack: string \| undefined) => void` | Called after each caught error. |
+| `onReset` | `(error: unknown, componentStack: string \| undefined) => void` | Called when `resetError()` runs, before the children render again. |
+| `options` | `ExceptionOptions` | Options for the report, as for [`Bugsee.logException`](/sdk/react_native/manual/crash-error-reporting#options): `{ domain }`. |
+
+The prop types are exported as `ErrorBoundaryProps` and `ErrorBoundaryFallbackProps`.
+
+## Fallback
+
+`fallback` takes two forms.
+
+**An element**, rendered as is:
+
+```tsx
+Something went wrong.}>
+
+
+```
+
+**A function**, called with an `ErrorBoundaryFallbackProps` object, so the fallback can show the error and offer a retry:
+
+```tsx
+import { Button, Text, View } from 'react-native';
+import { ErrorBoundary, type ErrorBoundaryFallbackProps } from '@bugsee/react-native';
+
+function ProfileFallback({ error, resetError }: ErrorBoundaryFallbackProps) {
+ return (
+
+ Profile failed to load: {String(error)}
+
+
+ );
+}
+
+export function ProfileScreen() {
+ return (
+ }>
+
+
+ );
+}
+```
+
+| Field | Type | Description |
+| --- | --- | --- |
+| `error` | `unknown` | The value that was thrown. It is not always an `Error`. |
+| `componentStack` | `string \| undefined` | The React component stack of the error. |
+| `resetError` | `() => void` | Clears the error and renders the children again. |
+
+`componentStack` arrives just after the error: the fallback's first render gets `undefined`, and it renders again once React has supplied the stack.
+
+## Resetting
+
+`resetError()` calls `onReset` with the error and component stack, then clears the boundary's state, so `children` render again from scratch. Reset whatever state caused the error first (in `onReset`, or before calling `resetError`); otherwise the children throw again and the fallback comes back.
+
+```tsx
+ cartStore.reload()}
+ fallback={({ resetError }) => }
+>
+
+
+```
+
+A new error after a reset is caught and reported again. The same error object is not reported twice; see below.
+
+## What is reported
+
+For each caught error, the boundary:
+
+1. Reports it as a handled **error** report, like [`Bugsee.logException`](/sdk/react_native/manual/crash-error-reporting#reporting-handled-errors). The component stack is attached as the innermost cause of the exception (named `ErrorBoundary Error`). The thrown value itself is not changed: its `cause` is left alone.
+2. Calls `onError(error, componentStack)`.
+
+Details:
+
+- **Once per error.** The boundary shares the SDK's record of reported errors. An error object that was already reported (for example with `logException`) is not reported again, but `onError` is still called.
+- **Bad options do not stop the report.** If `options` fails validation, the boundary logs a `console.warn` (`[Bugsee] ErrorBoundary options rejected; reporting without options`) and reports the error without options, rather than throwing during error handling.
+- **`detect.crash` does not apply.** The boundary reports even when `detectAndReportCrash` (`com.bugsee.option.detect.crash`) is `false`, as `logException` does. That option turns off only the automatic handlers.
+- **Before launch** the report is dropped, as a `logException` call is; the fallback still renders.
+- The report's severity is the error default, `High`, unless you change it; see [Report severity](/sdk/react_native/manual/crash-error-reporting#report-severity).
+
+## What it does not catch
+
+An error boundary catches errors thrown while React renders the components below it, in their lifecycle methods and in their constructors. Like every React error boundary, it does not catch errors thrown:
+
+- in event handlers, such as an `onPress` callback;
+- in asynchronous code: promises, `setTimeout`, `await`ed calls;
+- by the boundary itself, including its `fallback`;
+- outside React rendering.
+
+Those reach Bugsee through the global handlers instead, as crashes or errors; see [What is captured automatically](/sdk/react_native/manual/crash-error-reporting#what-is-captured-automatically). An error thrown by the fallback goes to the next boundary up or, with none, to the `Bugsee.wrap` root reporter, which reports it as a crash.
+
+## Differences from 6.x
+
+| | 6.x (`react-native-bugsee`) | 7.x (`@bugsee/react-native`) |
+| --- | --- | --- |
+| Import | `Bugsee.ErrorBoundary` | `import { ErrorBoundary } from '@bugsee/react-native'` |
+| Children | A node, or a function returning the nodes | A `ReactNode` only. Function-as-children is not supported. |
+| Reset helper passed to a `fallback` function | `resetErrorBoundary` | `resetError` |
+| Component stack | Set as the caught error's `cause` | Attached to the report only; the error is not changed |
+| Report options | none | `options: { domain }` |
+
+`fallback`, `onError` and `onReset` keep their roles. If you passed a function as the boundary's children in 6.x, render its result as an element instead (` ` rather than `{() => }`), and rename `resetErrorBoundary` to `resetError` in your fallback.
+
+The reset helper has a different name in each version: 6.x passes `resetErrorBoundary` to a `fallback` function, 7.x passes `resetError`. See the [6.x page](/sdk/react_native/v6/errorboundary) for the 6.x API.
+
+## Related pages
+
+- [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting): what is reported automatically, and `logException`.
+- [Report handler](/sdk/react_native/report-handler): add labels or attachments to the reports a boundary sends.
+- [Error boundary (6.x)](/sdk/react_native/v6/errorboundary): the previous version of this page.
diff --git a/docs/sdk/react_native/events-and-traces.mdx b/docs/sdk/react_native/events-and-traces.mdx
new file mode 100644
index 0000000..b7569e2
--- /dev/null
+++ b/docs/sdk/react_native/events-and-traces.mdx
@@ -0,0 +1,125 @@
+---
+title: "Custom events & traces"
+description: "Record custom events and traces on the report timeline with Bugsee React Native SDK 7.x: Bugsee.event and Bugsee.trace, the values they accept, and how invalid input is rejected."
+sidebar_position: 10
+slug: "/sdk/react_native/events-and-traces"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Besides what Bugsee captures automatically, you can add your own signals to the session a report replays:
+
+- **Events** mark that something happened (`payment_processed`, `onboarding_skipped`), optionally with parameters.
+- **Traces** follow how one value changes over time (`cart_total`, `logged_in`), so you can see its state right before a problem.
+
+Both are recorded on the report timeline, next to the video, logs and network events. They keep recording during a [blackout](/sdk/react_native/lifecycle#blackout), which hides only what describes the screen.
+
+Calls made before `Bugsee.launch` are not held until launch. Record events and traces after `launch`.
+
+## Custom events
+
+`Bugsee.event(name, params?)` records a named event:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// Without parameters
+Bugsee.event('payment_processed');
+
+// With parameters
+Bugsee.event('payment_processed', {
+ amount: 125,
+ currency: 'USD',
+ items: [{ sku: 'A-100', quantity: 2 }],
+ coupon: null,
+});
+```
+
+`params` is a plain object. Leave it out (or pass `undefined`) for an event without parameters; the event is then recorded with no parameters at all, not with an empty object.
+
+### Accepted parameter values
+
+Each value in `params`, at any depth, is one of (`EventParamValue`):
+
+| Value | Rules |
+| --- | --- |
+| `string` | |
+| `number` | Finite (no `NaN` or `Infinity`), and smaller than 263 in magnitude. |
+| `boolean` | |
+| `null` | Recorded as `null` on both platforms. |
+| array | Of accepted values. |
+| plain object | Of accepted values. A member whose value is `undefined` is left out, as `JSON.stringify` does. |
+
+Objects and arrays can nest up to 16 levels deep.
+
+The parameters are checked and **copied** when you call `event`, so changing your object afterward does not change what was recorded.
+
+### What is rejected
+
+`event` throws synchronously, and records nothing, when its input is outside that set. The message names the path of the bad value, such as `params.items[0].added`:
+
+| Input | Thrown |
+| --- | --- |
+| `name` that is not a string | `TypeError` |
+| `name` that is an empty string | `RangeError` |
+| `params` that is `null`, an array, or not a plain object | `TypeError` |
+| A `Date`, `Map`, `Set`, typed array, class instance, function, `bigint` or `symbol` value | `TypeError` |
+| `undefined` as an array element | `TypeError` |
+| An object or array that contains itself (a cycle) | `TypeError` |
+| A non-finite number, or one of 263 or more in magnitude | `RangeError` |
+| Nesting deeper than 16 levels | `RangeError` |
+
+:::note[Changed from 6.x]
+6.x accepted `null` as "no parameters". In 7.x, `Bugsee.event('name', null)` throws `TypeError`: leave the argument out instead.
+:::
+
+Convert values the SDK does not accept before you pass them, for example a `Date` to `date.toISOString()` and a `Map` to `Object.fromEntries(map)`.
+
+## Custom traces
+
+`Bugsee.trace(name, value)` records the current value of a trace. Each call adds a new point for that name, so call it whenever the value changes:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.trace('credit_balance', 15); // number
+Bugsee.trace('current_location', 'USA'); // string
+Bugsee.trace('logged_in', true); // boolean
+```
+
+The value (`TraceValue`) is a `string`, a `boolean`, or a finite `number` smaller than 263 in magnitude. A boolean is recorded as a boolean on both platforms, not as `0` or `1`.
+
+`trace` throws synchronously, and records nothing, for:
+
+| Input | Thrown |
+| --- | --- |
+| `name` that is not a string | `TypeError` |
+| `name` that is an empty string | `RangeError` |
+| A value that is not a string, number or boolean (including `null` and `undefined`) | `TypeError` |
+| A non-finite number, or one of 263 or more in magnitude | `RangeError` |
+
+## Handling the checks
+
+Because both calls throw on invalid input, guard calls whose input you do not control, so a bad value does not break the code path that records it:
+
+```ts
+import Bugsee, { type EventParams } from '@bugsee/react-native';
+
+function recordEvent(name: string, params?: EventParams): void {
+ try {
+ Bugsee.event(name, params);
+ } catch (error) {
+ console.warn('Bugsee event not recorded:', error);
+ }
+}
+```
+
+The types `EventParams`, `EventParamValue` and `TraceValue` are exported, so TypeScript catches most invalid values at compile time.
+
+## Related pages
+
+- [User & session data](/sdk/react_native/user-session-data): the user identifier and attributes.
+- [Breadcrumbs](/sdk/react_native/breadcrumbs): user and system events on the same timeline.
+- [Console logs](/sdk/react_native/logs): log lines with the report.
diff --git a/docs/sdk/react_native/expo.mdx b/docs/sdk/react_native/expo.mdx
new file mode 100644
index 0000000..9766427
--- /dev/null
+++ b/docs/sdk/react_native/expo.mdx
@@ -0,0 +1,201 @@
+---
+title: "Expo"
+description: "Setting up Bugsee React Native SDK 7.x in an Expo app with the config plugin: its options, what it writes on expo prebuild, and its limits."
+sidebar_position: 2
+slug: "/sdk/react_native/expo"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Expo apps regenerate `ios/` and `android/` on every `expo prebuild`, so native edits made by hand do not survive. `@bugsee/react-native` ships an Expo config plugin that makes the Bugsee build edits for you on each prebuild: the Bugsee Gradle plugin, the Hermes debug-id hooks, the source-map uploads and the iOS dSYM upload on Archive.
+
+The config plugin covers the **build**. Your app still starts the SDK from JavaScript with `Bugsee.launch`, as on [Installation](/sdk/react_native/installation#4-launch-bugsee).
+
+## Requirements
+
+The same as for any `@bugsee/react-native` app: React Native 0.81 or later with the New Architecture, Hermes, iOS 15.0 or later (15.1 with CocoaPods; see [Installation](/sdk/react_native/installation#requirements)) and Android API 21 or later. Any Expo SDK whose React Native is 0.81 or later meets this; the package's own Expo example uses Expo SDK 57 with React Native 0.86. The plugin edits Groovy Gradle files only; see [Limits](#limits).
+
+:::caution[No Expo Go]
+The package contains native code, so it does not run in Expo Go: the native module is looked up when the package loads, and is missing there. Use a [development build](https://docs.expo.dev/develop/development-builds/introduction/) instead.
+:::
+
+## 1. Add the package
+
+```sh
+yarn add @bugsee/react-native@beta
+```
+
+`npm install` and `pnpm add` work the same way; see [Installation](/sdk/react_native/installation#1-add-the-package), including the [pnpm notes](/sdk/react_native/installation#pnpm).
+
+## 2. Add the plugin
+
+Add `@bugsee/react-native` to `plugins` in `app.json` (or `app.config.js`):
+
+```json title="app.json"
+{
+ "expo": {
+ "plugins": [
+ ["@bugsee/react-native", { "appToken": { "ios": "YOUR_IOS_APP_TOKEN", "android": "YOUR_ANDROID_APP_TOKEN" } }]
+ ]
+ }
+}
+```
+
+`appToken` is either one string for both platforms or one token per platform. Bugsee app tokens are per platform, so the object form is the usual one. A token may contain only letters, digits, `.`, `_` and `-`; anything else, such as a placeholder like ``, fails the prebuild.
+
+## 3. Run prebuild
+
+```sh
+npx expo prebuild
+```
+
+Run it again whenever you change the plugin's options. The plugin's edits are its own: a later prebuild with a new value replaces them, and one without an option removes what that option wrote, with one exception. Turning `autoLaunch` off does not remove the `com.bugsee.app-token` entry that an earlier prebuild added to `AndroidManifest.xml`, so the SDK would still start before your code calls `Bugsee.launch`. After turning `autoLaunch` off, run a clean prebuild (`npx expo prebuild --clean`) or delete that entry yourself.
+
+Release builds then upload their source maps, and Archives upload their dSYMs, whenever a real token is set.
+
+:::caution[7.0.0-beta1 and 7.0.0-beta2: Android Release builds need `chmod`]
+In 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) the package's shell scripts are published without the executable bit. The `hermesCommand` the plugin writes runs `hermesc-preserve-js.sh` directly, so an Android Release build on macOS or Linux fails with "Permission denied". Run `chmod +x node_modules/@bugsee/react-native/scripts/*.sh` after each install, for example from a `postinstall` script; see [Symbolication: Android](/sdk/react_native/symbolication/android#1-javascript-source-maps). The iOS bundle phase the plugin writes runs its script through `/bin/bash` and is not affected.
+:::
+
+## 4. Launch the SDK
+
+Launch from JavaScript as in a bare app:
+
+```ts title="index.js"
+import { Platform } from 'react-native';
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+Bugsee.launch(
+ Platform.OS === 'ios' ? 'YOUR_IOS_APP_TOKEN' : 'YOUR_ANDROID_APP_TOKEN',
+ createDefaultLaunchOptions(),
+);
+```
+
+See [Installation](/sdk/react_native/installation#4-launch-bugsee) for what `launch` does and resolves to, and [Configuration](/sdk/react_native/configuration) for the options. To have Android start the SDK before JavaScript runs instead, see [`autoLaunch`](#auto-launch-on-android).
+
+## Plugin options
+
+| Option | Type | Default | What it does |
+| --- | --- | --- | --- |
+| `appToken` | string, or `{ ios?: string; android?: string }` | none | The token the build uploads use. Android: `app_token` in `android/bugsee.properties`. iOS: written into the Archive dSYM post-action, and into the bundle phase when `uploadSourcemaps` is on, so an Archive started from the Xcode GUI, which does not inherit a shell environment, still has it. A value that is not token-shaped fails the prebuild. |
+| `uploadSourcemaps` | boolean | `true` | Upload the composed JavaScript source map of Release builds. `false` writes `bugseeUploadSourcemaps=false` into `android/gradle.properties` and `BUGSEE_UPLOAD_SOURCEMAPS=false` into the iOS bundle phase. |
+| `uploadSymbols` | boolean | `true` | Upload native symbols. `false` removes the iOS Archive dSYM post-action (including one an earlier prebuild left) and, on Android, disables the Bugsee Gradle plugin's `uploadBugsee*` tasks (R8 mapping, NDK symbols, build info) in a marked block. Source maps follow `uploadSourcemaps`. |
+| `nativeCrashReporting` | boolean | `true` | Android native (NDK) crash reporting. On: writes `plugin.ndk.enabled=true` for a real token and adds `com.bugsee:bugsee-android-ndk`. `false`: skips the flag, removes that dependency and excludes the package's NDK artifact. |
+| `symbolicateReactNativeFrameworks` | boolean | `false` | Make `pod install` download React Native's own dSYMs, so React frames in iOS crashes symbolicate. See [React Native's dSYMs](#react-native-dsyms-on-ios). |
+| `autoLaunch` | boolean | `false` | Android only. Writes the `com.bugsee.app-token` manifest meta-data, so the native SDK launches at process start. See [Auto-launch on Android](#auto-launch-on-android). |
+| `endpoint` | string | none (production) | A self-hosted, staging or regional Bugsee API base. See [Custom endpoint](#custom-endpoint). |
+| `gradlePluginVersion` | string | the version the package is built against (4.0.8 in `7.0.0-beta3`) | The `com.bugsee.android.gradle` version to declare. |
+
+## What the plugin changes
+
+### Android
+
+- **`android/settings.gradle`**: adds `mavenCentral()` to `pluginManagement { repositories { … } }`. The Bugsee Gradle plugin is published to Maven Central, which Gradle does not search for plugins unless told to. If there is no `repositories` block, it adds the Gradle Plugin Portal, Google and Maven Central together, since declaring any block replaces Gradle's implicit Plugin Portal.
+- **`android/build.gradle`**: declares `com.bugsee.android.gradle` with `apply false`, at the plugin's version. A declaration that is already there, whoever wrote it, is taken as the plugin's own pin and its version follows the package's on each prebuild.
+- **`android/app/build.gradle`**: applies `com.bugsee.android.gradle`, points `react.hermesCommand` at the package's Hermes wrapper (which keeps the JavaScript so the debug id can reach the bytecode), applies the package's `scripts/bugsee-sourcemaps.gradle`, and adds the NDK dependency unless `nativeCrashReporting` is `false`.
+- **`android/bugsee.properties`**: `app_token`, `plugin.ndk.enabled` and `plugin.endpoint`, as the options set them. A missing or placeholder token is left out.
+- **`android/gradle.properties`**: `bugseeUploadSourcemaps=false` when `uploadSourcemaps` is `false`.
+- **`AndroidManifest.xml`**: the `com.bugsee.app-token` meta-data with `autoLaunch`, and the endpoint meta-data with `endpoint`.
+
+The plugin never removes or changes a line of your own code, on a clean or a `--no-clean` prebuild. It adds its own marked lines, replaces only those, and rewrites exactly one of yours, `react.hermesCommand`, keeping any trailing comment. A `bugsee-android-ndk` dependency of your own is never touched: the plugin then adds none and says so in the prebuild log.
+
+The plugin writes no `ndk { debugSymbolLevel … }`: the Bugsee Gradle plugin uploads native symbols from the unstripped libraries, whatever that level says, so it is your own choice for Google Play. Earlier versions of the config plugin wrote a `SYMBOL_TABLE` block under a `// bugsee-symbol-table:` comment; the next prebuild removes it if you have not changed it.
+
+### iOS
+
+- **"Bundle React Native code and images" build phase**: the call to React Native's `react-native-xcode.sh` is swapped for the package's `bugsee-xcode.sh`, which runs React Native's script, then composes the Hermes source map, gives the bundle and the map a debug id, and uploads the map. The rest of Expo's phase stays as it is.
+- **Shared schemes**: an Archive post-action that uploads the dSYMs with `bugsee-cli`, in every shared scheme under `ios/`. Without a real token it stops before it runs `bugsee-cli`.
+- **`Info.plist`**: `BugseeReactNativeEndpoint` when `endpoint` is set.
+- **`Podfile`**: a marked `# @generated begin bugsee-symbolicate-prebuilt` … `# @generated end bugsee-symbolicate-prebuilt` block with `symbolicateReactNativeFrameworks`.
+
+### Uploads without a token
+
+No upload runs with a missing token or the placeholder token (`00000000-0000-4000-8000-000000000000`). The source-map upload, the Archive dSYM post-action and the Bugsee Gradle plugin's mapping, symbol and build uploads each skip with one line in the build log, and the build or Archive carries on. For the post-action, the line is:
+
+```text
+warning: bugsee: dSYM upload skipped: the app token is the placeholder
+```
+
+A failed source-map upload warns and does not fail the build.
+
+:::note[Committed native projects]
+If you commit `ios/` (`project.pbxproj` and the shared scheme) or `android/bugsee.properties`, they carry the token. Keep `android/bugsee.properties` out of version control if the token is private.
+:::
+
+## Auto-launch on Android
+
+With `autoLaunch: true` and a real Android token, the plugin writes the token as `com.bugsee.app-token` application meta-data. The SDK then launches itself at process start on Android, before any JavaScript runs.
+
+```json title="app.json"
+["@bugsee/react-native", { "appToken": { "ios": "YOUR_IOS_APP_TOKEN", "android": "YOUR_ANDROID_APP_TOKEN" }, "autoLaunch": true }]
+```
+
+On Android, do not call `Bugsee.launch` then. The SDK is already running, so `launch` would resolve `true` but not apply its options (logging a warning to logcat when the call carries options), while the JavaScript side applied them; see [Launching again](/sdk/react_native/lifecycle#launching-again). Call `Bugsee.attach()` instead, which wires up the JavaScript layer (exception handlers and console capture) from the options the SDK is running with. See [Attach to a running SDK](/sdk/react_native/lifecycle#attach-to-a-running-sdk).
+
+```ts
+import { Platform } from 'react-native';
+import Bugsee from '@bugsee/react-native';
+
+if (Platform.OS === 'android') {
+ Bugsee.attach();
+} else {
+ Bugsee.launch('YOUR_IOS_APP_TOKEN');
+}
+```
+
+iOS has no auto-launch: launch it from JavaScript. A placeholder token is never written to the manifest.
+
+Two consequences of auto-launch on Android:
+
+- **Launch options from JavaScript are not applied.** The SDK starts from the manifest, before your options object exists. Configure it with `com.bugsee.option.*` application meta-data in `AndroidManifest.xml` (in an Expo app, through a config plugin of your own; the Bugsee plugin writes none), or call `Bugsee.relaunch(options)` after `attach()` to restart the session with your options.
+- **Reports lack the JavaScript details.** At process start the package registers only the React Native SDK type and version. `launch` and `relaunch` replace that with the full identity (React Native version, JavaScript engine, development build), but `attach()` does not, so until a `relaunch`, the session's reports carry the React Native wrapper type and version without those details.
+
+## Custom endpoint
+
+To send everything to a self-hosted, staging or regional Bugsee API, set `endpoint`:
+
+```json title="app.json"
+["@bugsee/react-native", { "appToken": "YOUR_APP_TOKEN", "endpoint": "https://bugsee.example.com" }]
+```
+
+The value is the API base: `https://`, a host, an optional port and an optional path, with no credentials, query, fragment or `/v2` (each reader adds the API version itself). Anything else fails the prebuild. Unset, the default, everything stays on Bugsee's production API.
+
+Set, it reaches every upload and the runtime:
+
+- **Android**: `plugin.endpoint` in `android/bugsee.properties`, for the Gradle plugin's uploads and the source-map upload, and `com.bugsee.reactnative.endpoint` application meta-data for the SDK.
+- **iOS**: `BUGSEE_ENDPOINT` in the bundle phase (source maps, when `uploadSourcemaps` is on) and in the Archive dSYM post-action, and `BugseeReactNativeEndpoint` in `Info.plist` for the SDK.
+- **Runtime**: `Bugsee.launch()` and `relaunch()` use it whenever their options carry no endpoint; an endpoint you pass yourself wins. `getLaunchOptions()` reads it back. With `autoLaunch`, it is also written as the auto-launched SDK's `com.bugsee.option.$$ENDPOINT`, unless your manifest already has one, which is then left as it is.
+
+## React Native dSYMs on iOS
+
+React Native's prebuilt `React.xcframework` ships without dSYMs, so after an Archive the `React` frames in a crash stay raw addresses while your own and Bugsee's frames symbolicate. React Native downloads the dSYMs only when `pod install` runs with `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1`.
+
+```json title="app.json"
+["@bugsee/react-native", { "appToken": "YOUR_IOS_APP_TOKEN", "symbolicateReactNativeFrameworks": true }]
+```
+
+`expo prebuild` then adds `ENV['RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS'] ||= '1'` to the top of `ios/Podfile`, and a later prebuild without the option removes it. A value you export yourself, such as `0`, wins.
+
+It is off by default because of the trade-off: `pod install` makes an extra download, and React Native fetches the dSYMs in the same step as the prebuilt framework, so a failed download drops the prebuilt React for that install, and a failure while unpacking aborts `pod install`. The variable also does nothing for a `React-Core-prebuilt` pod already in `ios/Pods` or the CocoaPods cache; see [Symbolication: iOS](/sdk/react_native/symbolication/ios).
+
+## Limits
+
+Where the plugin cannot make an edit with certainty, it refuses the prebuild with one error that names the file, the reason and the fix, and writes nothing. It refuses:
+
+- a Kotlin DSL `settings.gradle.kts`, `build.gradle.kts` or app `build.gradle.kts`. The refusal does not depend on what the file contains, so making the edits by hand does not get past it, whatever the error message suggests. With Kotlin DSL files, remove `@bugsee/react-native` from `plugins`, which also drops its iOS edits, and make every edit by hand, as in [Symbolication: Android](/sdk/react_native/symbolication/android) and [Symbolication: iOS](/sdk/react_native/symbolication/ios);
+- a Gradle file it cannot read for sure: a string that does not close on its line, a comment or string still open at the end of the file, braces that do not balance, or a `/` that could start a slashy string as well as divide;
+- a `react.hermesCommand` that spans several lines or shares its line with another statement after `;`;
+- an anchor brace that shares its line with code: a one-line `dependencies { … }`, a `buildscript { … }; …`, or a one-line `pluginManagement` or `repositories` block;
+- a `gradlePluginVersion` option, or an NDK version baked into the package, that is not a plain version string.
+
+On iOS, the prebuild fails when there is no shared `.xcscheme` under `ios/`, because the dSYM post-action goes into the shared schemes.
+
+The feedback package, `@bugsee/react-native-feedback`, needs no config plugin; see [Feedback](/sdk/react_native/feedback).
+
+## Related pages
+
+- [Installation](/sdk/react_native/installation): requirements and launching the SDK.
+- [Symbolication](/sdk/react_native/symbolication/overview): what each upload is for.
+- [Lifecycle & status](/sdk/react_native/lifecycle): `launch`, `attach` and status.
diff --git a/docs/sdk/react_native/faq.md b/docs/sdk/react_native/faq.md
new file mode 100644
index 0000000..3fd606d
--- /dev/null
+++ b/docs/sdk/react_native/faq.md
@@ -0,0 +1,126 @@
+---
+title: "FAQ"
+description: "Practical questions and answers about Bugsee React Native SDK 7.x (beta): setup, tokens, crash testing, symbolication and known beta behavior."
+sidebar_position: 24
+slug: "/sdk/react_native/faq"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Upgrading from 6.x? See the [migration guide](/sdk/react_native/migration).
+
+**1. Which React Native versions does 7.x support?**
+
+React Native 0.81 or later, with the New Architecture enabled, on iOS 15.0 or later and Android API 21 or later. The New Architecture is the default from React Native 0.76; on 0.81 it can still be turned off, but this package requires it on, and its import fails on the legacy architecture. See [Overview](/sdk/react_native/overview#requirements).
+
+
+
+**2. Can I use JavaScriptCore instead of Hermes? What happens if I turn Hermes off?**
+
+Hermes is required, and JavaScriptCore is not supported. React Native removed JavaScriptCore from core in 0.81, so turning Hermes off means plugging in a third-party engine. The only one the ecosystem offers, `@react-native-community/javascriptcore`, did not work with current React Native when we tried it. On Android its JavaScriptCore cannot parse React Native's own bundle, and on iOS it fails to link on 0.87 and to `pod install` on 0.86. An app that turns Hermes off therefore usually cannot be built, before the Bugsee SDK is involved.
+
+Nothing in the SDK blocks or warns about it, and some code adapts to it. Reports carry `js-engine: jsc` (for any engine that is not Hermes), stack traces are parsed in both engines' formats, unhandled promise rejections use the standard promise library's tracker, and the source-map build hooks have a plain-bundle path. None of this has been tested, because no test app could be built, so treat it as unsupported. If you try it anyway, report what you find together with your engine and React Native versions. See [Overview](/sdk/react_native/overview#requirements).
+
+
+
+**3. Does it work in Expo Go?**
+
+No. The package contains native code, which Expo Go does not have. Use a [development build](https://docs.expo.dev/develop/development-builds/introduction/) with `expo prebuild` and the config plugin. See [Expo](/sdk/react_native/expo).
+
+
+
+**4. What do the npm `latest` and `beta` tags mean?**
+
+For now both point at the current beta, so `yarn add @bugsee/react-native` and `yarn add @bugsee/react-native@beta` install the same version. Use `@beta` to keep following betas once a stable 7.x release exists, and install `@bugsee/react-native-feedback` at the same version. See [Installation](/sdk/react_native/installation#1-add-the-package).
+
+
+
+**5. pnpm stops the install with `ERR_PNPM_IGNORED_BUILDS`. What should I allow?**
+
+The package depends on `@bugsee/cli`, which has a `postinstall` script. pnpm 10 and later run no dependency's install script unless the project decides, and pnpm 11 fails until it does. The CLI binary comes from a platform-specific optional dependency, so the script is only a download fallback: set `'@bugsee/cli': false` under `allowBuilds` in `pnpm-workspace.yaml`, or `true` if your registry lacks `@bugsee/cli-`. React Native also needs `nodeLinker: hoisted`. See [pnpm](/sdk/react_native/installation#pnpm).
+
+
+
+**6. `launch` rejects with `E_TOKEN`. Why?**
+
+The token is missing, empty or blank. The package rejects it before launching the SDK. A token the backend rejects does not throw: `launch` resolves `false`. Remember that tokens are per platform; pick the right one from `Platform.OS`. See [What `launch` resolves to](/sdk/react_native/installation#what-launch-resolves-to).
+
+
+
+**7. `launch` resolved, but no report arrives.**
+
+Check that `launch` resolved `true`, and that you used the token of the platform you run. Capture comes up asynchronously, so a resolved `launch` does not yet mean recording; check `Bugsee.getStatus()` a moment later or use `Bugsee.onStatusChange`. `showReportDialog` and `upload` do nothing before launch. See [Installation](/sdk/react_native/installation#5-verify) and [Lifecycle & status](/sdk/react_native/lifecycle).
+
+
+
+**8. How do I test crash reporting?**
+
+Call `Bugsee.testJsCrash()` from a button handler, where nothing catches it, or `Bugsee.testNativeCrash()`, which raises the native SDK's test crash and ends the app. Relaunch the app afterward: a native crash report is sent at the next launch. Test on a physical device for iOS (see the next question). See [Testing crash reporting](/sdk/react_native/manual/crash-error-reporting#testing-crash-reporting).
+
+
+
+**9. Why are there no crash reports from the iOS Simulator?**
+
+In this beta, the iOS Simulator produces neither native nor JavaScript crash reports. Use a physical iPhone. See [Native crashes](/sdk/react_native/manual/crash-error-reporting#native-crashes).
+
+
+
+**10. Crash reports show minified JavaScript or raw native addresses.**
+
+The Release build did not upload its debug files. JavaScript frames need the source map, Android frames the R8 mapping and native symbols, iOS frames the dSYMs. An Expo app gets the uploads from the config plugin; a bare app needs a few build edits. Check the build log for `bugsee: uploaded source map `. React Native's own frames on iOS need `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1` at `pod install`. See [Symbolication](/sdk/react_native/symbolication/overview).
+
+
+
+**11. The build log says the upload was skipped because the token is the placeholder. What is that?**
+
+Without a real app token, or with the placeholder token `00000000-0000-4000-8000-000000000000`, the source-map upload and the iOS dSYM post-action skip with one line, and the build carries on. The Bugsee Gradle plugin skips its uploads only when no token is set at all; with Expo, the config plugin leaves a missing or placeholder token out of `android/bugsee.properties`, so those uploads skip too. In a bare app, do not put the placeholder in `android/bugsee.properties`. Give CI the token through `BUGSEE_APP_TOKEN`, or `android/bugsee.properties` written from your secrets. See [Uploads without a token](/sdk/react_native/expo#uploads-without-a-token) and [Tokens and endpoints](/sdk/react_native/symbolication/overview#tokens-and-endpoints).
+
+
+
+**12. Android reports have no `fetch` or XHR network events.**
+
+React Native sends these requests through OkHttp, and the Bugsee Gradle plugin is what lets the SDK record OkHttp traffic. Without the plugin applied to `android/app`, they are not recorded on Android. See [Installation](/sdk/react_native/installation#android) and [Symbolication: Android](/sdk/react_native/symbolication/android#2-the-bugsee-gradle-plugin).
+
+
+
+**13. With Android auto-launch, my JavaScript launch options are ignored.**
+
+With `autoLaunch`, the SDK starts from the manifest at process start on Android, before your options object exists, and you call `Bugsee.attach()` instead of `launch`. Configure it with `com.bugsee.option.*` manifest meta-data, or call `Bugsee.relaunch(options)` after `attach()`. Until a `relaunch`, the session's reports also lack the JavaScript details of the wrapper. See [Auto-launch on Android](/sdk/react_native/expo#auto-launch-on-android) and [Attach to a running SDK](/sdk/react_native/lifecycle#attach-to-a-running-sdk).
+
+
+
+**14. Can I set attributes or the user identifier before `launch`?**
+
+What the native SDKs do with them before launch is not specified in this beta. Set the identifier and attributes after the promise from `launch` resolves. See [Before launch](/sdk/react_native/user-session-data#before-launch).
+
+
+
+**15. After a development reload, logs or network events behave oddly.**
+
+Filters are JavaScript functions. After a reload, the filters stay on while nothing in the new runtime answers them: network events and breadcrumbs are lost, and logs are dropped on iOS and recorded unfiltered on Android, until your code calls the setters again. Call `setLogFilter`, `setNetworkFilter` and `setBreadcrumbFilter` first thing in your startup code. See the "Reloads" sections of [Console logs](/sdk/react_native/logs#reloads), [Network events](/sdk/react_native/network#reloads) and [Breadcrumbs](/sdk/react_native/breadcrumbs#reloads).
+
+
+
+**16. `logException` throws `TypeError: ExceptionOptions has unknown key "labels"`.**
+
+`logException` takes `{ domain }` only, as the 7.x native SDKs do; `labels` and `includeVideo` throw before anything is sent. Set labels from a report handler instead. There is no replacement for `includeVideo`. See [Options](/sdk/react_native/manual/crash-error-reporting#options) and [Report handler](/sdk/react_native/report-handler).
+
+
+
+**17. iOS build fails in `fmt` with "call to consteval function … is not a constant expression".**
+
+This is not caused by Bugsee: it affects React Native 0.81 and 0.82 with Xcode 26.4 or later, and the fix is to build the `fmt` pod as C++17 from your `Podfile`. See [iOS build fails in `fmt`](/sdk/react_native/installation#ios-build-fails-in-fmt).
+
+
+
+**18. A Release build fails with "Permission denied" on `hermesc-preserve-js.sh` or `bugsee-xcode.sh`.**
+
+In 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) the package's shell scripts are published without the executable bit. On Android (bare and Expo, on macOS or Linux) and in a bare app's iOS bundle phase, they are run directly and fail. Run `chmod +x node_modules/@bugsee/react-native/scripts/*.sh` after every install, for example from a `postinstall` script, or on iOS run the script through `/bin/bash`. See [Symbolication: Android](/sdk/react_native/symbolication/android#1-javascript-source-maps) and [Symbolication: iOS](/sdk/react_native/symbolication/ios#1-the-bundle-phase-javascript-source-maps).
+
+
+
+**19. Where are the 6.x answers?**
+
+See the [6.x documentation](/sdk/react_native/v6/installation), and the [release notes](/sdk/react_native/release-notes) for what each 7.x beta changed.
diff --git a/docs/sdk/react_native/feedback.md b/docs/sdk/react_native/feedback.md
index 517caa3..e444af7 100644
--- a/docs/sdk/react_native/feedback.md
+++ b/docs/sdk/react_native/feedback.md
@@ -1,24 +1,154 @@
---
title: "Feedback"
-description: "Enable in-app user-to-support messaging in React Native by launching Bugsee's built-in feedback UI and configuring a default greeting."
-sidebar_position: 6
+description: "Installing and using @bugsee/react-native-feedback, the in-app feedback chat for Bugsee React Native SDK 7.x: showing the chat, the greeting, message listeners and chat colors."
+sidebar_position: 18
slug: "/sdk/react_native/feedback"
---
-Bugsee implements a built-in single-threaded messenger to allow your users to communicate with your support and developers.
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
-## Feedback activity
+Bugsee includes an in-app chat that lets your users talk to your support team and developers. In 7.x it ships as its own package, `@bugsee/react-native-feedback`, so apps that never show it do not depend on it.
-To start feedback activity from within your application:
+## Installation
-```javascript
-Bugsee.showFeedbackUI();
+Add the feedback package next to `@bugsee/react-native`. The two must be the **same release**: install both at the same version, or both with the `@beta` tag. Nothing enforces it: the package's peer dependency accepts any `@bugsee/react-native` from `7.0.0-beta3` on.
+
+```sh
+yarn add @bugsee/react-native@beta @bugsee/react-native-feedback@beta
```
-## Default greeting
+`npm install` and `pnpm add` work the same way. The requirements are those of `@bugsee/react-native`: React Native 0.81 or later with the New Architecture, Hermes, iOS 15.1 or later (15.0 with Swift Package Manager) and Android API 21 or later; see [Installation](/sdk/react_native/installation#requirements).
+
+The native side comes with the package, at the versions the core package pins:
+
+| Platform | What is added |
+| --- | --- |
+| Android | Autolinking adds the Android feedback module, `com.bugsee:bugsee-android-feedback`, at the same version as the core Android SDK (7.4.2 in this beta). No Gradle changes. |
+| iOS | With CocoaPods, run `pod install`: the podspec fetches the sources of the iOS feedback package, `bugsee/feedback-spm`, at the same version as the core iOS SDK (7.0.0-beta7 in this beta), and compiles them. With React Native 0.87 and later, Swift Package Manager resolves that package instead. |
+
+The package has no Expo config plugin.
+
+## Showing the chat
-Default greeting can be set on the server in your application settings. However, for the cases when network is not available, you can set default greeting on the client as well:
+Open the chat from your own UI, such as a "Contact support" button, with `showFeedbackUI()`:
-```javascript
-Bugsee.setDefaultFeedbackGreeting("Hi! How can we help?");
+```tsx
+import { Button } from 'react-native';
+import { showFeedbackUI } from '@bugsee/react-native-feedback';
+
+function ContactSupportButton() {
+ return showFeedbackUI()} />;
+}
```
+
+Call the feedback functions after `Bugsee.launch` has resolved. On Android, `showFeedbackUI()` does nothing before launch. On iOS the chat opens before launch, but nothing is sent until the SDK has launched. If the native module is not linked (for example, the app was not rebuilt after installing the package), importing `@bugsee/react-native-feedback` throws.
+
+Before the conversation starts, the chat shows an e-mail screen. On this screen the user can leave an address for replies. The screen stays until the user continues or skips it. When the [user identifier](/sdk/react_native/user-session-data#user-identity) contains an `@`, the chat takes it as the user's address and does not ask. Android checks the identifier once per launch, at the first feedback call, so set the identifier before your first feedback call. On iOS, the chat's messages carry the user identifier when the user gave no address.
+
+## Greeting
+
+`setGreeting(greeting)` sets the app's greeting, shown at the top of an empty conversation. `null` clears it. Android: a greeting set in the Bugsee dashboard takes precedence over the app's. iOS: the chat shows the app's greeting; a greeting set in the dashboard is not used in this beta.
+
+```ts
+import { setGreeting } from '@bugsee/react-native-feedback';
+
+setGreeting('Hi! How can we help?');
+```
+
+A value that is neither a string nor `null` throws `TypeError`.
+
+## Message listeners
+
+`setListener(listener)` tells you about chat traffic, for example to show a badge when support has replied:
+
+```ts
+import { setListener } from '@bugsee/react-native-feedback';
+
+setListener({
+ onNewMessagesReceived(messages) {
+ // New messages from your support team
+ console.log(`${messages.length} new support message(s)`);
+ },
+ onNewMessageSent(message) {
+ // A message the user just sent
+ },
+});
+
+// Later: stop listening
+setListener(null);
+```
+
+| Callback | Receives | When |
+| --- | --- | --- |
+| `onNewMessagesReceived` | `readonly string[]` | New messages arrived from your support team. |
+| `onNewMessageSent` | `string` | The user sent a message. |
+
+- Both callbacks are optional, and both are called on the JavaScript thread.
+- There is one listener at a time. A later call replaces it, and `null` removes it.
+- A value that is not an object or `null` (an array, a function) throws `TypeError`.
+- A listener is JavaScript state: after a JavaScript reload, call `setListener` again.
+
+## Appearance
+
+The `appearance` object sets the chat's colors. Assign a hex color to a property:
+
+```ts
+import { Platform } from 'react-native';
+import { appearance } from '@bugsee/react-native-feedback';
+
+appearance.backgroundColor = '#101828';
+appearance.outgoingBubbleColor = '#7f56d9';
+
+if (Platform.OS === 'android') {
+ appearance.actionBarColor = '#101828';
+}
+```
+
+- Colors are CSS hex strings: `#RGB`, `#RGBA`, `#RRGGBB` or `#RRGGBBAA`, alpha last. The `#` is optional, and `#RRGGBB` is opaque.
+- A value that is not a string throws `TypeError`; a string that is not a hex color throws `RangeError`.
+- Each color exists on Android, on iOS, or on both. Setting one on a platform that does not have it throws `RangeError`, so check `Platform.OS` for the platform-only ones.
+- Reading a property returns the value you last set in this JavaScript runtime, or `undefined`.
+
+| Property | Android | iOS |
+| --- | --- | --- |
+| `backgroundColor` | Yes | Yes |
+| `incomingBubbleColor`, `outgoingBubbleColor` | Yes | Yes |
+| `incomingTextColor`, `outgoingTextColor` | Yes | Yes |
+| `inputTextColor` | Yes | Yes |
+| `titleTextColor` | Yes | Yes |
+| `emailBackgroundColor` | Yes | Yes |
+| `emailContinueActiveColor`, `emailContinueNotActiveColor` | Yes | Yes |
+| `actionBarColor`, `actionBarButtonBackgroundClickedColor` | Yes | |
+| `bottomDelimiterColor` | Yes | |
+| `dateTextColor` | Yes | |
+| `emailContinueClickedColor` | Yes | |
+| `emailSkipTextColor`, `emailSkipBackgroundClickedColor` | Yes | |
+| `errorTextColor` | Yes | |
+| `inputTextHintColor` | Yes | |
+| `loadingBarBackgroundColor`, `loadingTextColor` | Yes | |
+| `versionChangedBackgroundColor`, `versionChangedTextColor` | Yes | |
+| `barsColor` | | Yes |
+| `closeButtonColor` | | Yes |
+| `emailSkipColor` | | Yes |
+| `inputBackgroundColor` | | Yes |
+| `navigationBarColor` | | Yes |
+
+Native SDK reference for what each color paints: [Android feedback appearance](/sdk/android/appearance#feedbackappearance). The iOS documentation has no such list; the caution below says which colors the iOS chat applies.
+
+:::caution[iOS: most chat colors are not applied in this beta]
+On iOS, the colors are accepted, but the chat in this beta uses only some of them. It paints its background with `backgroundColor`, and its e-mail screen with `emailBackgroundColor`, `emailSkipColor`, `emailContinueActiveColor` and `emailContinueNotActiveColor`. The message bubbles use the system accent color and gray, and the other colors do not change the chat.
+:::
+
+The colors of the bug report dialog are set separately, on `Bugsee.appearance`; see [Appearance](/sdk/react_native/appearance).
+
+## Privacy
+
+The messages a user sends, and the e-mail address they leave, are sent to Bugsee for your team to read. A webhook can receive them as the [`feedback.message.in`](/webhooks/events#feedbackmessagein) and [`feedback.message.out`](/webhooks/events#feedbackmessageout) events.
+
+## Related pages
+
+- [Appearance](/sdk/react_native/appearance): the report dialog's colors.
+- [User & session data](/sdk/react_native/user-session-data): the user identifier the chat reads.
+- [Installation](/sdk/react_native/installation): the core package.
diff --git a/docs/sdk/react_native/installation.mdx b/docs/sdk/react_native/installation.mdx
new file mode 100644
index 0000000..3086d03
--- /dev/null
+++ b/docs/sdk/react_native/installation.mdx
@@ -0,0 +1,201 @@
+---
+title: "Installation"
+description: "Installing Bugsee React Native SDK 7.x in a React Native CLI (bare) app, launching it from JavaScript, and checking that reports arrive."
+sidebar_position: 1
+slug: "/sdk/react_native/installation"
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+This page covers a React Native CLI (bare) app, where you own the `ios/` and `android/` projects. If your app uses Expo prebuild, add the package as shown here, then follow [Expo](/sdk/react_native/expo) for the native setup.
+
+:::caution[Replacing 6.x]
+`@bugsee/react-native` replaces `react-native-bugsee` (6.x). They are different packages with different APIs, not an upgrade in place. Remove `react-native-bugsee` first; [Migrating from 6.x to 7.x](/sdk/react_native/migration) lists the API changes.
+:::
+
+## Requirements
+
+| | |
+| --- | --- |
+| React Native | 0.81 or later, with the New Architecture enabled |
+| JavaScript engine | Hermes (React Native's default) |
+| iOS | 15.0 or later (see the note below) |
+| Android | API 21 or later |
+
+The New Architecture is the default from React Native 0.76. On 0.81 it can still be turned off; this package requires it on. Hermes is required: JavaScriptCore is not supported (see the [FAQ](/sdk/react_native/faq) for what happens if you turn Hermes off).
+
+The Bugsee iOS SDK itself supports iOS 15.0. With CocoaPods, the podspec takes React Native's own minimum, which is 15.1, so that is the effective floor there.
+
+## 1. Add the package
+
+
+
+
+```sh
+yarn add @bugsee/react-native@beta
+```
+
+
+
+
+```sh
+npm install @bugsee/react-native@beta
+```
+
+
+
+
+```sh
+pnpm add @bugsee/react-native@beta
+```
+
+
+
+
+For now the npm `latest` and `beta` tags both point at this beta, so a plain `yarn add @bugsee/react-native` installs it too. The `@beta` form keeps following betas once a stable 7.x release exists.
+
+### pnpm
+
+React Native needs `nodeLinker: hoisted` under pnpm.
+
+pnpm 10 and later run no dependency's install script unless the project decides, and pnpm 11 fails the install until it does (`ERR_PNPM_IGNORED_BUILDS`). The package depends on `@bugsee/cli`, which uploads symbols and source maps and has a `postinstall` script. Its binary comes from a platform-specific optional dependency, so the script is only a download fallback for registry mirrors that lack those packages. Decide in `pnpm-workspace.yaml`:
+
+```yaml title="pnpm-workspace.yaml"
+allowBuilds:
+ '@bugsee/cli': false # true only if your registry lacks @bugsee/cli-
+```
+
+## 2. Native setup
+
+### iOS
+
+If your app uses React Native's Swift Package Manager integration (React Native 0.87 and later), the package's own `Package.swift` provides the SDK. React Native's autolinking references that package directly; there is no Bugsee-specific step to run.
+
+Otherwise (CocoaPods, on any React Native version) the package's podspec downloads the same XCFramework from `download.bugsee.com` during `pod install` and vendors it, so install pods as usual:
+
+```sh
+cd ios && pod install
+```
+
+Nothing is published to CocoaPods trunk, so you don't need `pod repo update`.
+
+For readable iOS crash reports in Release, a bare app also needs two build edits: point the **Bundle React Native code and images** build phase at the package's `bugsee-xcode.sh` (which uploads the JavaScript source map, with a token from `BUGSEE_APP_TOKEN` in, for example, `ios/.xcode.env.local`), and add the dSYM upload post-action to the scheme's Archive action. Both are described in [Symbolication: iOS](/sdk/react_native/symbolication/ios). Without them the app still builds and runs, but JavaScript and native frames in Release reports stay unsymbolicated.
+
+### Android
+
+Autolinking picks up the module. The app builds and launches with no Gradle changes.
+
+The package brings in the Android SDK together with its NDK crash reporting and OkHttp modules. Three things still need edits that autolinking cannot make:
+
+- **JavaScript source maps**: two edits in `android/app/build.gradle`, pointing `react.hermesCommand` at the package's Hermes wrapper and applying the package's `scripts/bugsee-sourcemaps.gradle`, which gives the bundle a debug id and uploads its map with `@bugsee/cli`. These do not need the Gradle plugin.
+- **R8/ProGuard mapping and native symbols**: uploaded by the **Bugsee Gradle plugin** (`com.bugsee.android.gradle`).
+- **Network capture of `fetch` and `XMLHttpRequest`**: React Native sends these through OkHttp, and the Bugsee Gradle plugin is what lets the SDK record OkHttp traffic. **Without the plugin, these requests are not recorded on Android.**
+
+All of these edits are listed in [Symbolication: Android](/sdk/react_native/symbolication/android). Without them the app still builds and runs, but Android reports carry no `fetch`/XHR network events, and JavaScript and native frames in Release reports stay unsymbolicated.
+
+## 3. Get your app tokens
+
+Bugsee app tokens are per platform: your iOS app and your Android app each have their own token in the Bugsee dashboard. Pick the right one at runtime from `Platform.OS`, as in the next step.
+
+## 4. Launch Bugsee
+
+Call `Bugsee.launch` once, as early as you can. The top of `index.js` is a good place: `` follows native animation events only from the moment `@bugsee/react-native` is first evaluated, so importing it there masks correctly from the start.
+
+```ts title="index.js"
+import { AppRegistry, Platform } from 'react-native';
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+import App from './App';
+import { name as appName } from './app.json';
+
+const token =
+ Platform.OS === 'ios' ? '' : '';
+
+const options = createDefaultLaunchOptions();
+options.captureLogs = true;
+
+Bugsee.launch(token, options);
+
+// Bugsee.wrap captures the view hierarchy and reports uncaught render errors.
+AppRegistry.registerComponent(appName, () => Bugsee.wrap(App));
+```
+
+What this does:
+
+- **`createDefaultLaunchOptions()`** returns an empty options object for the running platform. It is not pre-filled: every option you leave unset keeps the native SDK's own default. See [Configuration](/sdk/react_native/configuration) for every option.
+- **`Bugsee.launch(token, options)`** takes the options object as is; there is no serialize step to call. It also accepts a plain map of `com.bugsee.option.*` keys, for options you build or merge yourself:
+
+ ```ts
+ Bugsee.launch(token, {
+ 'com.bugsee.option.capture.logs': true,
+ 'com.bugsee.option.config.duration': 60,
+ });
+ ```
+
+- **`Bugsee.wrap(App)`** renders your root component unchanged, next to an invisible anchor the SDK uses to find the view tree, inside a reporter for uncaught render errors. Without it, reports carry no view hierarchy, and an uncaught render error is not reported (render errors do not reach the global error handler); see [Render errors](/sdk/react_native/manual/crash-error-reporting#render-errors).
+
+`launch` also installs the JavaScript exception handlers (uncaught errors and unhandled promise rejections) and, once the native SDK has answered, forwards `console.*` output to Bugsee.
+
+### What `launch` resolves to
+
+`launch` resolves to `true` when the SDK started, and `false` when it declined, for example because the backend rejected the token. Declining is not an error, so `launch` does not reject for it. A `launch` while the SDK is already running also resolves `true`, but its options are not applied; see [Launching again](/sdk/react_native/lifecycle#launching-again).
+
+A missing, empty or blank token is rejected before the SDK is launched, with an error whose `code` is `E_TOKEN`.
+
+Capture comes up asynchronously on both platforms, so a resolved `launch` does not mean recording has begun. Poll `Bugsee.getStatus()` or subscribe with `Bugsee.onStatusChange` when you need to know; see [Lifecycle & status](/sdk/react_native/lifecycle).
+
+:::tip[Register handlers before launch]
+If you use a [report handler](/sdk/react_native/report-handler), call `Bugsee.setReportHandler` **before** `Bugsee.launch`. A handler installed afterward misses the reports that launch recovers, such as a crash from the previous run.
+:::
+
+## 5. Verify
+
+Build and run the app, then send a test report:
+
+1. Check that the SDK is running (capture comes up shortly after `launch` resolves, so check a moment later, or use `Bugsee.onStatusChange`):
+
+ ```ts
+ import Bugsee, { Status } from '@bugsee/react-native';
+
+ async function checkBugsee() {
+ const status = await Bugsee.getStatus();
+ console.log(status === Status.Launched ? 'Bugsee is running' : `Bugsee status: ${status}`);
+ }
+ ```
+
+2. Open the report dialog with `Bugsee.showReportDialog()`, fill it in and send it. To check crash reporting instead, call `Bugsee.testJsCrash()`, which throws a JavaScript error at the call site (in a development build, React Native also shows its error screen), or `Bugsee.testNativeCrash()`, which raises the native SDK's own test crash (a Java `RuntimeException` on Android, an `NSException` on iOS).
+3. Open your app in the Bugsee dashboard and find the report, with its video, logs and network events. On Android, `fetch`/XHR network events appear only with the Bugsee Gradle plugin applied; see [Android](#android).
+
+:::note
+`showReportDialog` and `upload` do nothing before `launch()`. If no report arrives, check that `launch` resolved `true` and that you used the token of the platform you are running.
+:::
+
+## Troubleshooting
+
+### iOS build fails in `fmt`
+
+{/* cspell:ignore consteval fmtlib */}
+
+On React Native 0.81 and 0.82 with Xcode 26.4 or later, the iOS build can fail in the `fmt` pod with "call to consteval function … is not a constant expression". This is not caused by Bugsee: those React Native versions build `fmt` 11.0.2 from source, which newer Apple clang rejects as C++20 ([fmtlib/fmt#4740](https://github.com/fmtlib/fmt/issues/4740)). React Native 0.83 and later ship `fmt` 12 and are not affected.
+
+Build that one pod as C++17 from the `post_install` block of `ios/Podfile`, after `react_native_post_install(...)`, then run `pod install` again:
+
+```ruby title="ios/Podfile"
+ installer.pods_project.targets.each do |target|
+ next unless target.name == 'fmt'
+ target.build_configurations.each do |config|
+ config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'
+ end
+ end
+```
+
+## Next steps
+
+- [Configuration](/sdk/react_native/configuration): launch options for both platforms.
+- [Lifecycle & status](/sdk/react_native/lifecycle): stop, relaunch and the lifecycle events.
+- [Symbolication](/sdk/react_native/symbolication/overview): readable stack traces in Release builds.
+- [Privacy](/sdk/react_native/privacy/overview): mask views and filter captured data.
diff --git a/docs/sdk/react_native/lifecycle.mdx b/docs/sdk/react_native/lifecycle.mdx
new file mode 100644
index 0000000..0a42e82
--- /dev/null
+++ b/docs/sdk/react_native/lifecycle.mdx
@@ -0,0 +1,208 @@
+---
+title: "Lifecycle & status"
+description: "Launching, stopping, relaunching and attaching to Bugsee React Native SDK 7.x, reading its status, and subscribing to its lifecycle events."
+sidebar_position: 4
+slug: "/sdk/react_native/lifecycle"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+The SDK can be launched, stopped and relaunched at runtime. You can ask for its current status at any time, and subscribe to its lifecycle events: status transitions, report assembly and upload, blackouts and crash relaunches.
+
+## Launch, stop, and relaunch
+
+Each call returns a promise that settles once the native SDK has answered.
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+async function start(): Promise {
+ return Bugsee.launch('', createDefaultLaunchOptions());
+}
+
+async function shutDown(): Promise {
+ await Bugsee.stop();
+}
+
+// Relaunch with a new set of options (no token: the session's own is kept)
+async function restartWithoutVideo(): Promise {
+ const options = createDefaultLaunchOptions();
+ options.captureVideo = false;
+ return Bugsee.relaunch(options);
+}
+```
+
+| Method | Resolves to | Notes |
+| --- | --- | --- |
+| `launch(token, options?)` | `boolean` | `true` when the SDK started, and also when it was already running or launching: that second launch does not apply its options (see [Launching again](#launching-again)). `false` when it declined, for example because the backend rejected the token. A missing or blank token rejects with `code` `E_TOKEN`. |
+| `relaunch(options?)` | `boolean` | Restarts an already-launched session with a new set of options. `true` when the SDK restarted, on both platforms. |
+| `stop()` | `boolean` | Resolves `true` once the native SDK has stopped; it never resolves `false`. |
+| `attach()` | `void` | Wires up the JavaScript layer when the native SDK was launched without JavaScript. See [Attach to a running SDK](#attach-to-a-running-sdk). |
+
+`launch` and `relaunch` take the options object or a plain `com.bugsee.option.*` map; see [Configuration](/sdk/react_native/configuration). Declining is a normal outcome rather than an error, so `launch` does not reject when the SDK declines.
+
+### What `launch` sets up
+
+Besides starting the native SDK, `launch` (and `relaunch`) prepare the JavaScript side:
+
+1. Identifies the app to the SDK as a React Native app before launching, so a report produced during startup says it came from React Native.
+2. Installs the global JavaScript exception handlers, for uncaught errors (`ErrorUtils`) and unhandled promise rejections. `detectAndReportCrash: false` (`com.bugsee.option.detect.crash`) turns their reporting off.
+3. Launches the native SDK.
+4. Once the native call resolves, patches `console.*` so each line still prints and is also forwarded to Bugsee. A rejected launch does not install the patch. A later call does not wrap the functions again, but re-reads `com.bugsee.option.capture.logs`, so a relaunch can turn console forwarding off or on.
+
+Both settings follow the options passed to each call, not the options in effect. A `relaunch(options)` whose options leave out `com.bugsee.option.capture.logs` turns console forwarding back on, and one that leaves out `com.bugsee.option.detect.crash` turns JavaScript exception reporting back on, even if an earlier call set them to `false`.
+
+:::caution[Hermes promise rejection tracker]
+On Hermes, the last caller of `enablePromiseRejectionTracker` wins, and Hermes has no way to read the current tracker. Another library that installs a tracker after `Bugsee.launch` replaces Bugsee's, and unhandled promise rejections are then no longer reported.
+:::
+
+### Launching again
+
+A `launch` while the SDK is already running or launching starts nothing and resolves `true`, on both platforms. The options it carries are **not applied**: the session keeps the options it started with, and on Android, a call that carried options logs a warning to logcat. The JavaScript side still follows the new options, though (see [What `launch` sets up](#what-launch-sets-up)), so the two can disagree. To change options, call `relaunch(options)` instead.
+
+A `launch` made while the SDK is still stopping differs per platform. Android: it resolves `false` and does not launch. iOS: it resolves `true`, but does not launch either. Launch again once `stop()` has resolved.
+
+### A resolved launch is not live capture
+
+When `launch` resolves `true`, the SDK has started, but how far it has got differs per platform:
+
+- **Android**: `launch` resolves once capture is up. The status is already `Launched`. The exception is a `launch` that joins one already in progress, which resolves at once.
+- **iOS**: `launch` resolves while the status is still `Launching`, and recording may not have begun yet. A `launch` made while the app is in the background resolves `true` too, and the SDK starts when the app becomes active.
+
+Check [the status](#querying-status) or wait for the `Launched` event rather than assuming.
+
+On iOS, a report-creating call made while the status is still `Launching` would be dropped. The SDK works around this: `Bugsee.logException`, `Bugsee.upload`, `Bugsee.createReport` and `Bugsee.showReportDialog` calls made while the status is `Launching` are held, then replayed in order once it is `Launched`. They are dropped instead if the SDK reports `Stopping` or `Stopped`, if 30 seconds pass without `Launched`, or if 64 calls are already held. A call made while nothing is held runs at once.
+
+## Before launch
+
+Most calls need a launched SDK. Before `launch`:
+
+- `Bugsee.upload` and `Bugsee.showReportDialog` do nothing, and `Bugsee.createReport` resolves `null`.
+- `Bugsee.log` lines, `Bugsee.logException` errors and `Bugsee.notify` items are dropped.
+- `Bugsee.startBlackout()` is honored on both platforms: call it before `launch` to keep the first seconds of a session hidden from the video. See [Privacy: Video](/sdk/react_native/privacy/video).
+
+:::tip[Install the report handler first]
+Call `Bugsee.setReportHandler` **before** `Bugsee.launch`. During launch the SDK recovers reports from the previous run, such as a crash, and a handler installed afterward misses them. See [Report handler](/sdk/react_native/report-handler).
+:::
+
+## Attach to a running SDK
+
+The native SDK can be launched before any JavaScript runs:
+
+- **Android**: the native SDK can launch itself at process start from the `com.bugsee.app-token` manifest meta-data. The [Expo config plugin](/sdk/react_native/expo#auto-launch-on-android) writes it with `autoLaunch: true`.
+- **iOS**: there is no auto-launch, but your app can launch the SDK from its own native code, for example in its `AppDelegate`.
+
+In that case, call `Bugsee.attach()` instead of `launch`. It makes no launch call, and only sets up the JavaScript side:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.attach();
+```
+
+A `launch` would not start a second session either, but it would not apply its options, while the JavaScript side applied them; see [Launching again](#launching-again). `attach` instead reads the options the SDK is running with, and applies `com.bugsee.option.detect.crash` from them before it installs the exception handlers. Exception capture is held off while it reads, so an error raised in that gap is not reported, rather than being reported when the option turns out to be `false`. It then installs the console patch from the same options. If reading the options fails, the promise rejects, and neither the handlers nor the console patch are installed.
+
+`attach` works the same on both platforms. On iOS, attaching to an SDK your native code launched has not been verified on a device in this beta.
+
+A report the SDK produces before JavaScript runs (such as a crash recovered from the previous run) is attributed to React Native on Android, where the package identifies itself at process start. On iOS the package does that when React Native loads it, so a report produced before then may not be.
+
+Reports carry the React Native SDK type and version but not the JavaScript details (React Native version, JavaScript engine, development build): `attach()` does not register them. Only `launch` and `relaunch` do, so a `relaunch` after `attach()` adds them for the rest of the session. A `relaunch(options)` is also the way to apply launch options from JavaScript, since the SDK started with the options of the manifest (Android) or of your native code (iOS).
+
+## Querying status
+
+`Bugsee.getStatus()` resolves to the SDK's current status, a `Status` value:
+
+| `Status` | Value | Meaning |
+| --- | --- | --- |
+| `Stopped` | `0` | Not running. Also reported when the SDK was never launched. |
+| `Launching` | `1` | Starting up. |
+| `Launched` | `2` | Running. |
+| `Stopping` | `3` | Shutting down. |
+
+```ts
+import Bugsee, { Status } from '@bugsee/react-native';
+
+async function isRunning(): Promise {
+ return (await Bugsee.getStatus()) === Status.Launched;
+}
+```
+
+A status value this version of the SDK does not recognize, from a newer native SDK, is reported as `Stopped` rather than passed through.
+
+### Status changes
+
+`Bugsee.onStatusChange(listener)` calls `listener` with the new `Status` on each transition, and returns a subscription with `remove()`:
+
+```ts
+import Bugsee, { Status } from '@bugsee/react-native';
+
+const subscription = Bugsee.onStatusChange((status) => {
+ if (status === Status.Launched) {
+ // Capture is up.
+ }
+});
+
+// Later
+subscription.remove();
+```
+
+Status changes are derived from the lifecycle events: the `Launching`, `Launched`, `Stopping` and `Stopped` events each produce one call, and no other event does.
+
+## Lifecycle events
+
+`Bugsee.onLifecycleEvent(listener)` subscribes to every lifecycle event the SDK dispatches, and returns a subscription with `remove()`. Each event is a `LifecycleEvent`:
+
+```ts
+interface LifecycleEvent {
+ name: string; // for example 'RelaunchedAfterCrash'
+ reportId?: string; // only on the events that carry one
+}
+```
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const subscription = Bugsee.onLifecycleEvent((event) => {
+ if (event.name === 'RelaunchedAfterCrash') {
+ // The previous session ended with a crash.
+ }
+ if (event.name === 'AfterReportUploaded') {
+ console.log('uploaded report', event.reportId);
+ }
+});
+
+// Unsubscribe
+subscription.remove();
+```
+
+Both platforms dispatch these events, by the same names:
+
+| Event | `reportId` | Description |
+| --- | --- | --- |
+| `Launching` / `Launched` | no | The SDK is starting / has started. |
+| `Stopping` / `Stopped` | no | The SDK is stopping / has stopped. |
+| `BlackoutStarted` / `BlackoutEnded` | no | Visual capture paused / resumed by `startBlackout()` / `endBlackout()`. |
+| `RelaunchedAfterCrash` | no | The SDK launched and found a crash from the previous session. |
+| `BeforeReportShown` / `AfterReportShown` | no | The report UI is about to be / has been shown. No report exists yet at this point. |
+| `BeforeReportAssembled` / `AfterReportAssembled` / `ReportAssemblyFailed` | yes | Report assembly stages. |
+| `BeforeReportUploaded` / `AfterReportUploaded` | yes | Report upload start / success. |
+| `ReportUploadFailedWithFutureRetry` / `ReportUploadFailed` | yes | Upload failed, to be retried / permanently. |
+
+How events are delivered:
+
+- They arrive off the main thread on both platforms and reach JavaScript as they come.
+- Nothing is queued while there is no subscriber, so a subscription made after launch does not replay what it missed. Ask `getStatus()` for the current state rather than rebuilding it from events.
+- An event this version of the SDK does not know is delivered unchanged rather than dropped, so a newer native SDK can reach your listener. Compare `name` against the names you handle and ignore the rest.
+
+## Blackout
+
+`Bugsee.startBlackout()` and `Bugsee.endBlackout()` bracket a window in which everything that describes the screen is suppressed (the video, the report screenshot, touches and the view hierarchy), while logs, network events, custom events and traces keep recording. `Bugsee.isBlackout()` resolves to the current state. Use a blackout to hide a sensitive flow without stopping the SDK; see [Privacy: Video](/sdk/react_native/privacy/video). To shut the SDK down, use `stop()`.
+
+## Related pages
+
+- [Installation](/sdk/react_native/installation): the first launch.
+- [Configuration](/sdk/react_native/configuration): the options `launch` and `relaunch` take.
+- [Expo](/sdk/react_native/expo): Android auto-launch with the config plugin.
+- [Report handler](/sdk/react_native/report-handler): changing reports before they are sent.
diff --git a/docs/sdk/react_native/logs.mdx b/docs/sdk/react_native/logs.mdx
new file mode 100644
index 0000000..59f3a5d
--- /dev/null
+++ b/docs/sdk/react_native/logs.mdx
@@ -0,0 +1,179 @@
+---
+title: "Console logs"
+description: "How Bugsee React Native SDK 7.x captures console output and native logs, how to write your own lines with Bugsee.log, and how to rewrite or drop lines with setLogFilter."
+sidebar_position: 8
+slug: "/sdk/react_native/logs"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Bugsee attaches the log lines your app wrote before a report to that report, on the same timeline as the video and network events. In React Native, those lines come from three places: your JavaScript `console.*` calls, the native logs of the app (including React Native itself and native modules), and lines you send with `Bugsee.log`.
+
+## Automatic console capture
+
+After `Bugsee.launch` resolves, the package patches these `console` methods. Each call still prints as before, and the line is then forwarded to the native SDK:
+
+| Method | Level |
+| --- | --- |
+| `console.error` | `Error` |
+| `console.warn` | `Warning` |
+| `console.log` | `Info` |
+| `console.info` | `Info` |
+| `console.debug` | `Debug` |
+
+`console.trace` and the other `console` methods are not patched and are not forwarded.
+
+The arguments of one call become one line, converted with `String()` and joined with a space, the way a console prints them. Objects are **not** serialized to JSON: `console.log('user', { id: 7 })` is recorded as `user [object Object]`. This keeps fields you did not mean to log (a token inside an object, say) out of the report. Log the values you need explicitly, for example with `JSON.stringify`.
+
+The patch is installed once `launch` (or `relaunch`, or [`attach`](/sdk/react_native/lifecycle#attach-to-a-running-sdk)) resolves, whether it resolves `true` or `false`, so `console` calls made before that are not forwarded. Only a rejection skips it. It is installed only once, and works the same in development and release builds.
+
+### Native logs
+
+The native SDKs also capture the app's native log output:
+
+- **Android**: the app's logcat output, which includes lines from React Native itself and from native modules.
+- **iOS**: standard output and standard error (`print`, `NSLog`), and the log lines of React Native itself and of native modules, at these levels: trace as `Debug`, info as `Info`, warning as `Warning`, error and fatal as `Error`. Lines written only to the unified log (`os_log`) are not captured.
+
+### Each line once
+
+One `console.*` call can also reach the native log (as a `ReactNativeJS` logcat line on Android, as a React Native log line or on standard output on iOS), mainly in development builds. The SDK recognizes that copy and drops it, in development and release builds alike, so each console line is recorded, and reaches your [log filter](#filtering-log-lines), once.
+
+A later `console.*` call or `Bugsee.log` with the same text is a separate line and is kept. On iOS, though, one standard output or standard error line with the same text as a console call, arriving within 2 seconds of it, is treated as that call's copy and dropped.
+
+## Capture options
+
+| Option | Key | Default | Description |
+| --- | --- | --- | --- |
+| `captureLogs` | `com.bugsee.option.capture.logs` | `true` | Capture logs automatically: `console.*` output, the native logs above. `false` stops all of it; lines you send with `Bugsee.log` are still recorded. |
+| `captureLogsLevel` | `com.bugsee.option.capture.logs.level` | `LogLevel.Verbose` | The most verbose level captured; less severe lines are dropped. See [Which lines the level applies to](#which-lines-the-level-applies-to). |
+| `logsUseAllSources` (Android) | `com.bugsee.option.capture.logs.allsources` | `false` | Read all logcat buffers instead of the default sources. |
+
+The console patch reads `com.bugsee.option.capture.logs` at each `launch`, `relaunch` and `attach`, so a `relaunch` with the option changed turns forwarding off or back on.
+
+```ts
+import Bugsee, { LogLevel, createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+// Keep Error, Warning and Info. On Android this applies to logcat lines only; on iOS, to every line.
+options.captureLogsLevel = LogLevel.Info;
+
+Bugsee.launch('', options);
+```
+
+### Which lines the level applies to
+
+| Platform | `captureLogsLevel` applies to |
+| --- | --- |
+| Android | Only the lines the SDK reads from logcat (React Native core and native modules). It does **not** apply to `console.*` lines forwarded by the package or to `Bugsee.log` lines: with `LogLevel.Info`, a `console.debug` line is still recorded. |
+| iOS | Every line the SDK records, including `console.*` lines and `Bugsee.log` lines. |
+
+See [Configuration](/sdk/react_native/configuration) for every option.
+
+## Writing your own lines
+
+`Bugsee.log(message, level?, requiresFiltering?)` records one line in the Bugsee log:
+
+```ts
+import Bugsee, { LogLevel } from '@bugsee/react-native';
+
+// Default level (Info)
+Bugsee.log('User tapped Checkout');
+
+// Explicit level
+Bugsee.log('Payment succeeded', LogLevel.Info);
+Bugsee.log('Retrying request', LogLevel.Warning);
+Bugsee.log('Upload failed', LogLevel.Error);
+
+// Run the log filter on this line (the filter below redacts token=...)
+function onSessionRefreshed(sessionToken: string): void {
+ Bugsee.log(`Session refreshed: token=${sessionToken}`, LogLevel.Info, true);
+}
+```
+
+| Argument | Type | Default | Description |
+| --- | --- | --- | --- |
+| `message` | `string` | | The line. |
+| `level` | `LogLevel` | `LogLevel.Info` | `Error`, `Warning`, `Info`, `Debug` or `Verbose`. |
+| `requiresFiltering` | `boolean` | `false` | Whether your [log filter](#filtering-log-lines) runs on this line. |
+
+`Bugsee.log` goes straight to the native `Bugsee.log`; it does not go through the `console` patch. Lines are recorded even with `com.bugsee.option.capture.logs` set to `false`, which turns off only what is captured automatically. Lines sent before `launch` are dropped.
+
+`Bugsee.log` throws synchronously, and records nothing, when:
+
+| Input | Thrown |
+| --- | --- |
+| `message` that is not a string | `TypeError` |
+| `level` that is not a `LogLevel` value (`1` to `5`) | `RangeError` |
+| `requiresFiltering` that is not a boolean | `TypeError` |
+
+### `requiresFiltering`
+
+By default, the log filter **skips** lines you send with `Bugsee.log`. Pass `true` for a line that may carry data your filter should handle, such as a value that came from the user. The filter then runs on it once, the same way it runs on captured lines.
+
+## Filtering log lines
+
+`Bugsee.setLogFilter(callback)` installs a filter that sees each log line before it is recorded. Return the line (or a changed copy) to keep it, or `null` to drop it:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.setLogFilter((line) => {
+ // Drop noisy lines entirely
+ if (line.startsWith('[heartbeat]')) {
+ return null;
+ }
+ // Redact tokens
+ return line.replace(/token=[^&\s]+/g, 'token=');
+});
+```
+
+The filter sees `console.*` lines, the native log lines, and `Bugsee.log` lines sent with `requiresFiltering: true`.
+
+Install the filter **before** `Bugsee.launch`, at the top of your startup code. Lines recorded before `setLogFilter` runs are recorded unfiltered. A filter set before `launch` stays in effect after it, and after `relaunch`.
+
+The callback receives the line's text, a string. It can change only the text: the level and timestamp of the line stay as they were.
+
+| Result | Effect |
+| --- | --- |
+| A string | Replaces the line. Return the line unchanged to keep it as is. |
+| `null` or `undefined` | Drops the line. |
+| A `Promise` | Waited on; its value is treated the same way. |
+| Any other value (a number, an object) | Drops the line. |
+| The callback throws, or the promise rejects | Drops the line. |
+
+There is one filter at a time. A later call replaces it, and `setLogFilter()` or `setLogFilter(null)` removes it, so lines are recorded without one. A value that is not a function, `null` or `undefined` throws `TypeError` and leaves the previous filter in place. The callback is chosen when a line arrives, so replacing it while a line is being filtered changes the next line, not that one.
+
+:::note
+The SDK sets a log filter of its own on the native side, on both platforms, to drop the duplicate console copies described in [Each line once](#each-line-once). A log filter you set from native code with `setLogEventFilter` is replaced by it. Filter logs with `Bugsee.setLogFilter` instead.
+:::
+
+### Async filters and deadlines
+
+Your callback runs asynchronously, and it may return a promise. Capture does not wait for the answer.
+
+A line is never recorded unfiltered because the filter was late:
+
+- **Android**: a line the filter has not answered within about **10 seconds** is dropped. A later answer has no effect.
+- **iOS**: there is no deadline. A late answer is still applied, and the line is recorded then, with the timestamp it was captured at. A line the filter never answers is never recorded.
+
+Every captured line in the session (all but `Bugsee.log` lines sent without `requiresFiltering`) goes through the filter, so keep it fast and synchronous where you can. A filter that awaits slow work for each line can make lines arrive late or be dropped.
+
+### Reloads
+
+A filter is a function in the JavaScript runtime. When the runtime reloads (a development reload, for example), lines still waiting for an answer are dropped. After the reload, until the new runtime calls `setLogFilter`, the platforms differ:
+
+- **Android**: lines are recorded **unfiltered**.
+- **iOS**: lines are **dropped**, because nothing in the new runtime answers the filter.
+
+Neither is what you want, so call `setLogFilter` first thing in your startup code, before anything logs.
+
+See [Privacy: Console logs](/sdk/react_native/privacy/logs) for redaction guidance.
+
+## Related pages
+
+- [Privacy: Console logs](/sdk/react_native/privacy/logs): redacting log lines.
+- [Network events](/sdk/react_native/network): the matching network filter.
+- [Configuration](/sdk/react_native/configuration): every launch option.
+- [Lifecycle & status](/sdk/react_native/lifecycle): what works before launch.
diff --git a/docs/sdk/react_native/manual/bug-reporting.mdx b/docs/sdk/react_native/manual/bug-reporting.mdx
new file mode 100644
index 0000000..fcfff17
--- /dev/null
+++ b/docs/sdk/react_native/manual/bug-reporting.mdx
@@ -0,0 +1,237 @@
+---
+title: "Bug reporting"
+description: "Let users and your code file bug reports with Bugsee React Native SDK 7.x: the built-in triggers, the report dialog, silent upload, and building a report with createReport."
+sidebar_position: 1
+slug: "/sdk/react_native/manual/bug-reporting"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Bug reports cover something that is wrong but did not crash the app. Your users can raise one with a gesture, or you can open the report dialog, or submit a report silently, from your own code. Crashes and handled errors are covered separately, in [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting).
+
+All three calls on this page need a launched SDK; see [Before launch](#before-launch).
+
+## Built-in report triggers
+
+The native SDKs can open the report dialog on their own, without any call from your code. These triggers are launch options:
+
+| Key | Accessor | Platforms | Default | Opens the report dialog when |
+| --- | --- | --- | --- | --- |
+| `com.bugsee.option.reporting.triggers.shake` | none | both | `true` | The user shakes the device. |
+| `com.bugsee.option.reporting.triggers.screenshot` | none | both | `false` | The user takes a screenshot. |
+| `com.bugsee.option.reporting.triggers.notification-bar` | `triggerByNotification` | Android | `true` | The user taps the Bugsee entry in the notification bar. |
+| `com.bugsee.option.reporting.triggers.broadcast` | none | Android | `false` | An Android broadcast intent asks for a report. |
+
+Turn the shake trigger off, and the screenshot trigger on, at launch:
+
+```ts
+import Bugsee, { AndroidLaunchOptions, createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.setCustomOption('com.bugsee.option.reporting.triggers.shake', false);
+options.setCustomOption('com.bugsee.option.reporting.triggers.screenshot', true);
+if (options instanceof AndroidLaunchOptions) {
+ options.triggerByNotification = false;
+}
+
+Bugsee.launch('', options);
+```
+
+The Android-only keys are not recognized on iOS, so set them only on an Android options object. The options that shape the dialog itself (required fields, the labels field, the priority selector) are listed under [Configuration: Reporting](/sdk/react_native/configuration#reporting).
+
+## Show the report dialog
+
+`Bugsee.showReportDialog(summary?, description?, severity?, labels?)` opens the standard reporting UI. Every argument is optional and only pre-fills the form: the user can still edit the values before sending.
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+// An empty form
+Bugsee.showReportDialog();
+
+// Pre-fill the summary and description
+Bugsee.showReportDialog('Checkout is frozen', 'The spinner never stops.');
+
+// Pre-fill everything, including severity and labels
+Bugsee.showReportDialog(
+ 'Checkout is frozen',
+ 'The spinner never stops.',
+ IssueSeverity.High,
+ ['checkout'],
+);
+
+// Severity only: leave the text fields out with undefined
+Bugsee.showReportDialog(undefined, undefined, IssueSeverity.Critical);
+```
+
+| Argument | Type | When omitted |
+| --- | --- | --- |
+| `summary` | `string` | The field is left empty. |
+| `description` | `string` | The field is left empty. |
+| `severity` | `IssueSeverity` | The SDK's default bug severity. |
+| `labels` | `readonly string[]` | No labels are pre-filled. |
+
+The call returns nothing (`void`) and does not tell you whether the user sent the report or dismissed the dialog. Subscribe to the `BeforeReportShown`, `AfterReportShown` and upload [lifecycle events](/sdk/react_native/lifecycle#lifecycle-events) to follow it.
+
+The dialog runs your report handler's `onBeforeReportCreated` before it opens; see [Report handler](/sdk/react_native/report-handler).
+
+## Silent upload
+
+`Bugsee.upload(summary, description, severity?, labels?)` creates a bug report and uploads it at once, without any UI. Use it when you have already collected the details in your own UI.
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+Bugsee.upload('Checkout frozen', 'Spinner never stops');
+
+Bugsee.upload('Checkout frozen', 'Spinner never stops', IssueSeverity.High, ['checkout']);
+```
+
+`summary` and `description` are required, and both must be strings; an empty string is accepted. An omitted `severity` gets the default bug severity, `com.bugsee.option.reporting.defaults.bug-priority` (`High` unless you set it), on both platforms. An omitted `labels` sends no labels.
+
+Like `showReportDialog`, `upload` returns `void`. Follow the upload with the `BeforeReportUploaded`, `AfterReportUploaded` and `ReportUploadFailed*` [lifecycle events](/sdk/react_native/lifecycle#lifecycle-events).
+
+:::warning
+Do not call `upload` from automated error paths. To report an error from code, use [`Bugsee.logException`](/sdk/react_native/manual/crash-error-reporting#reporting-handled-errors): an error report carries the stack trace and is grouped with the other occurrences of the same error.
+:::
+
+### Argument checks
+
+`upload` and `showReportDialog` check their arguments in JavaScript and throw synchronously, before anything reaches the native SDK:
+
+| Argument | Rule | Thrown |
+| --- | --- | --- |
+| `summary`, `description` | A string (required for `upload`, optional for `showReportDialog`). | `TypeError` |
+| `severity` | Omitted, or an integer from `1` to `5` (an `IssueSeverity` value). | `TypeError` for a non-number, `RangeError` for any other number |
+| `labels` | Omitted, or an array of strings. The array is copied. | `TypeError` |
+| a fifth argument | `upload` takes at most four arguments. 7.x has no `includeVideo`. | `TypeError` |
+
+`labels` is still an argument of both calls; only `Bugsee.logException` lost its per-call labels in 7.x (see [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting#reporting-handled-errors)).
+
+## Build a report yourself
+
+When you need to fill a report over time, attach files to it, or decide when it is sent, use `Bugsee.createReport()`. It resolves to a `BugseeCreatedReport` that you fill and then send with its own `upload()`:
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+// React Native's default TypeScript config has no DOM types, so declare the
+// global btoa the runtime provides (or use a base64 library).
+declare function btoa(data: string): string;
+
+async function reportCheckoutProblem(logText: string): Promise {
+ const report = await Bugsee.createReport();
+ if (report === null) {
+ return; // The SDK made no report: it is not launched.
+ }
+ await report.update({
+ summary: 'Checkout frozen',
+ description: 'The spinner never stops.',
+ severity: IssueSeverity.High,
+ labels: ['checkout'],
+ attributes: { cartSize: 3 },
+ });
+ await report.addDataAttachment(btoa(logText), {
+ name: 'checkout.log',
+ mimeType: 'text/plain',
+ });
+ const uploaded = await report.upload();
+ console.log('report handed off:', uploaded);
+}
+```
+
+`btoa` encodes only Latin-1 text; encode other text to bytes first, or use a base64 library.
+
+`createReport()` resolves `null` when the SDK made no report, for example before `launch`. The created report has these methods, each returning a promise:
+
+| Method | Resolves to | Description |
+| --- | --- | --- |
+| `read()` | `BugseeReportSnapshot` | The report's current fields; see [The snapshot](/sdk/react_native/report-handler#reading-a-report). |
+| `update(patch)` | `void` | Changes summary, description, severity, labels and attributes in one call; see [Changing a report](/sdk/react_native/report-handler#changing-a-report). |
+| `addFileAttachment(path, { name, mimeType? })` | `void` | Attaches a file. The file is copied when it is added; there is no `move` option on a created report. |
+| `addDataAttachment(base64, { name, mimeType? })` | `void` | Attaches bytes, given as a base64 string. |
+| `upload()` | `boolean` | Hands the report to the SDK for upload. |
+
+The patch, the snapshot and the attachment arguments are the same as on a [report handler](/sdk/react_native/report-handler)'s report, which has the details. A created report has no `id`, no `type` and no deadline: it stays open until you upload it.
+
+### One created report at a time
+
+Only one created report can be outstanding. A second `createReport()` before the first is uploaded rejects with a `BugseeReportError` whose `code` is `E_REPORT_CREATE_BUSY`. There is no call that discards a created report, so always finish one with `upload()`; the slot is otherwise freed only when the JavaScript runtime reloads. On iOS the slot stays taken until that upload has completed, so a `createReport()` made while the previous upload is still in progress also rejects.
+
+`upload()` ends the report. Every later call on it, including a second `upload()`, rejects with `E_REPORT_HANDLE_DEAD`, whatever the upload's result was. Call `createReport()` again for another report.
+
+What `upload()` resolves to differs by platform:
+
+- **Android**: the result the SDK reports for the upload.
+- **iOS**: always `true`, once the report is handed off, even when the SDK is not launched. It does not tell you whether the upload succeeded.
+
+### Platform differences
+
+| | Android | iOS |
+| --- | --- | --- |
+| Attachments on a created report | Up to 1000. | At most 3, each non-empty and at most 3 MiB. A further or larger one rejects with `E_REPORT_ATTACHMENT_REJECTED`. `mimeType` is ignored. |
+| When the report handler runs | `onBeforeReportCreated` runs inside `createReport()`, `onAfterReportCreated` at `upload()`. | Both callbacks run at `upload()`, after the created report's fields are copied, so a handler's `setLabels` replaces the labels you set. |
+
+## Before launch
+
+Before `launch`, `upload` and `showReportDialog` do nothing, and `createReport()` resolves `null`. Nothing is queued for later.
+
+On iOS, a call made while the SDK is still starting (status `Launching`) is held and replayed once it is `Launched`; see [A resolved launch is not live capture](/sdk/react_native/lifecycle#a-resolved-launch-is-not-live-capture).
+
+## Errors
+
+Created-report operations reject with a `BugseeReportError` for the codes below; match on its `code`, a `ReportErrorCode` value. Any other failure, such as an unexpected native fault, rejects with an ordinary error, so rethrow what you do not match.
+
+| `ReportErrorCode` | `code` | Meaning |
+| --- | --- | --- |
+| `CreateBusy` | `E_REPORT_CREATE_BUSY` | Another created report is still outstanding. |
+| `HandleDead` | `E_REPORT_HANDLE_DEAD` | The report was already uploaded. |
+| `AttachmentRejected` | `E_REPORT_ATTACHMENT_REJECTED` | The attachment was declined. |
+| `BadArgument` | `E_REPORT_BAD_ARGUMENT` | An argument failed validation; nothing was sent. |
+
+```ts
+import Bugsee, { BugseeReportError, ReportErrorCode } from '@bugsee/react-native';
+
+async function openReport() {
+ try {
+ return await Bugsee.createReport();
+ } catch (error) {
+ if (error instanceof BugseeReportError && error.code === ReportErrorCode.CreateBusy) {
+ return null; // Finish the outstanding report first.
+ }
+ throw error;
+ }
+}
+```
+
+## Default severities
+
+A report gets a default severity unless one is passed or set from a report handler. Change the defaults with these launch options:
+
+| Key | Default | Applies to |
+| --- | --- | --- |
+| `com.bugsee.option.reporting.defaults.crash-priority` | `IssueSeverity.Blocker` | Crash reports |
+| `com.bugsee.option.reporting.defaults.error-priority` | `IssueSeverity.High` | Error reports |
+| `com.bugsee.option.reporting.defaults.bug-priority` | `IssueSeverity.High` | Bug reports |
+
+```ts
+import Bugsee, { IssueSeverity, createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.setCustomOption('com.bugsee.option.reporting.defaults.bug-priority', IssueSeverity.Medium);
+
+Bugsee.launch('', options);
+```
+
+## Severity values
+
+`IssueSeverity` values: `VeryLow` (1), `Medium` (2), `High` (3), `Critical` (4), `Blocker` (5). Pass the constants rather than numbers; see the [enum reference](/sdk/react_native/configuration#enum-reference).
+
+## Related pages
+
+- [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting): handled errors and crashes.
+- [Report handler](/sdk/react_native/report-handler): change every report before it is sent.
+- [Lifecycle & status](/sdk/react_native/lifecycle): the report events.
+- [Feedback](/sdk/react_native/feedback): the in-app feedback chat.
diff --git a/docs/sdk/react_native/manual/crash-error-reporting.mdx b/docs/sdk/react_native/manual/crash-error-reporting.mdx
new file mode 100644
index 0000000..94e3b81
--- /dev/null
+++ b/docs/sdk/react_native/manual/crash-error-reporting.mdx
@@ -0,0 +1,197 @@
+---
+title: "Crash & error reporting"
+description: "What Bugsee React Native SDK 7.x reports automatically (JavaScript errors, unhandled promise rejections, render errors, native crashes), and how to report handled and unhandled errors yourself."
+sidebar_position: 2
+slug: "/sdk/react_native/manual/crash-error-reporting"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Most crashes and errors are reported **automatically** once `Bugsee.launch` has run: you do not need to call anything. This page lists what is captured and how each kind is reported, then covers the cases where you report something yourself: handled errors, errors your app treats as crashes, and checking that the pipeline works.
+
+Bugsee files two kinds of report here:
+
+- a **crash** report, for something that ended (or is about to end) the app, with the default severity `Blocker`;
+- an **error** report, for a handled, non-terminal error, with the default severity `High`.
+
+Release builds need source maps and native symbols uploaded for their stack traces to resolve to your source; see [Symbolication](/sdk/react_native/symbolication/overview).
+
+## What is captured automatically
+
+| Source | Reported as | Needs |
+| --- | --- | --- |
+| Uncaught JavaScript error that React Native reports as fatal | crash | `launch` |
+| JavaScript error reported to the global handler as non-fatal | error | `launch` |
+| Unhandled promise rejection | **error** | `launch` |
+| Uncaught render error (no error boundary catches it) | crash | [`Bugsee.wrap`](/sdk/react_native/installation#4-launch-bugsee) around your root component |
+| Render error caught by Bugsee's `` | error | [``](/sdk/react_native/error-boundary) |
+| Native crash | crash | `launch` |
+
+### JavaScript errors
+
+`Bugsee.launch` (and `relaunch`, and `attach`) installs a global error handler through React Native's `ErrorUtils`. The handler keeps the one that was installed before it and always calls it afterward, so React Native's own handling (the red error screen in a development build) still runs.
+
+- A **fatal** error is reported as a crash. The handler waits until the native SDK has taken the report, at most 1.5 seconds on iOS and 5 seconds on Android, and only then passes the error on, so the report is stored before the app goes down.
+- A **non-fatal** error is reported as an error, and passed on at once.
+
+### Unhandled promise rejections
+
+`launch` also installs a promise rejection tracker. An unhandled rejection is reported as an **error** report, not a crash, because it does not stop the app. In a development build, React Native's own warning for the rejection still appears.
+
+:::caution
+On Hermes, the last library to install a promise rejection tracker wins. Another library that installs one after `Bugsee.launch` replaces Bugsee's, and unhandled rejections are then no longer reported; see [Lifecycle & status](/sdk/react_native/lifecycle#what-launch-sets-up).
+:::
+
+### Render errors
+
+In React Native 0.81 and later (the minimum this SDK supports), an error thrown while rendering a component never passes through `ErrorUtils`: React hands it to React Native directly. The global handler above therefore does not see it.
+
+- **Uncaught render errors** are reported by `Bugsee.wrap`. It renders your root component inside a reporter that reports the error as a crash, renders nothing while the report is stored, then throws the same error again so React Native's fatal path still runs. Without `Bugsee.wrap`, an uncaught render error is not reported.
+- **Render errors you catch** with an error boundary are reported only by Bugsee's own [``](/sdk/react_native/error-boundary), as errors. An error boundary from React or another library catches the error before Bugsee sees it; call [`Bugsee.logException`](#reporting-handled-errors) from its `componentDidCatch` if you keep it.
+
+### Native crashes
+
+Crashes in native code are captured too:
+
+- **Android**: uncaught exceptions in Java and Kotlin code, and crashes in native (NDK) code.
+- **iOS**: uncaught Objective-C exceptions (`NSException`), and fatal signals (`SIGABRT`, `SIGSEGV`, `SIGBUS`, `SIGILL`, `SIGFPE` and `SIGTRAP`, which includes Swift runtime traps), whether raised by a hardware fault or by software (with the default `crashHandlerType`).
+
+On iOS, `crashHandlerType` and `crashSignals` choose how crashes are intercepted; see [iOS accessors](/sdk/react_native/configuration#ios-accessors). Other detectors (hangs, low-memory exits, HTTP errors) are launch options too; see [Detection](/sdk/react_native/configuration#detection).
+
+:::caution[iOS Simulator]
+In this beta, the iOS Simulator produces no crash reports: neither native crashes nor JavaScript crashes. Test crash reporting on a physical iPhone.
+:::
+
+:::caution[iOS: Xcode debugger and TestFlight]
+- **Debugger.** When the SDK launches while the Xcode debugger is attached, it does not intercept crashes for that session, and the debugger handles them instead. To test crash reporting, start the app from the device's home screen, not from Xcode.
+- **TestFlight.** In builds installed through TestFlight, the system can intercept crashes before Bugsee does. On test devices, turn off **Share With App Developers** in *Settings > Privacy & Security > Analytics & Improvements*. See the iOS [TestFlight builds](/sdk/ios/v7/installation#testflight-builds) notes.
+:::
+
+### Turning automatic reporting off
+
+`detectAndReportCrash: false` (`com.bugsee.option.detect.crash`) turns off native crash reporting, and also the reporting of uncaught JavaScript errors, unhandled promise rejections and uncaught render errors. The handlers stay installed and keep passing errors on; they just report nothing.
+
+It does not turn off what you report on purpose: `Bugsee.logException` and `` still report, and so does `Bugsee.logUnhandledException` (verified on Android; on iOS, where the crash is recovered at the next launch, this is not verified in this beta).
+
+The setting follows the options of each `launch` or `relaunch` call; see [What launch sets up](/sdk/react_native/lifecycle#what-launch-sets-up).
+
+## Reporting handled errors
+
+`Bugsee.logException(error, options?)` records a caught error as an **error** report, without crashing the app:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function loadProfile(): Promise {
+ try {
+ await fetchProfile();
+ } catch (error) {
+ Bugsee.logException(error);
+ showOfflineBanner();
+ }
+}
+```
+
+`error` can be any value. An `Error` (or a subclass) gives the best report: its name, message, stack and `cause` chain. For any other value, see [What a report carries](#what-a-report-carries).
+
+`logException` returns `void`. Before `launch` the native SDKs drop the error; on iOS, one logged while the SDK is still starting is held until it has launched (see [Lifecycle & status](/sdk/react_native/lifecycle#a-resolved-launch-is-not-live-capture)).
+
+### Options
+
+`options` is an `ExceptionOptions` object with one key:
+
+| Key | Type | Description |
+| --- | --- | --- |
+| `domain` | `string` | The exception domain. Android groups issues by it; iOS records it with the report. Non-empty, at most 256 characters. |
+
+```ts
+Bugsee.logException(error, { domain: 'checkout' });
+```
+
+The options are checked before anything is sent, and a bad option throws synchronously: a `TypeError` for an options value that is not a plain object, an unknown key or a non-string `domain`, and a `RangeError` for an empty `domain` or one over 256 characters.
+
+:::note[No per-call labels or `includeVideo`]
+In 7.x, `logException` takes `{ domain }` only, as the 7.x native SDKs do. `labels` and `includeVideo` throw `TypeError: ExceptionOptions has unknown key "labels"` (or `"includeVideo"`).
+
+Set labels from a [report handler](/sdk/react_native/report-handler) instead. A handler has no per-call context, so the labels it sets apply to every report it handles; check `report.type` to limit them to error reports. `includeVideo` has no replacement: neither SDK can leave the video out of one report. (`Bugsee.upload` and `Bugsee.showReportDialog` still take `labels`.)
+:::
+
+:::warning
+Do not call `Bugsee.upload` from automated error paths. Use `logException`, so the report carries the stack trace and is grouped with the other occurrences of the same error.
+:::
+
+## Reporting unhandled errors
+
+`Bugsee.logUnhandledException(error)` reports `error` as a **crash**. Use it for an error your app treats as fatal but that Bugsee's handlers did not see, for example because another error handler takes it first:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function onFatalError(error: unknown): Promise {
+ await Bugsee.logUnhandledException(error);
+ // Now end the session your own way.
+}
+```
+
+It returns a promise that resolves once the native SDK has the report, after at most 1.5 seconds on iOS and 5 seconds on Android. It never rejects. Await it before the app goes down, so the report is stored first.
+
+On iOS, the crash report is stored and sent at the next launch, as for any crash.
+
+For a handled, non-terminal error, use [`logException`](#reporting-handled-errors) instead. Automatic capture does not need either call.
+
+## Each error is reported once
+
+Bugsee remembers every error **object** it has reported, and does not report the same object again, whichever route sees it second: `logException`, `logUnhandledException`, the global handler, the rejection tracker, `` or `Bugsee.wrap`. An error that more than one route sees produces one report from the JavaScript layer.
+
+Three consequences:
+
+- If you log an error and then rethrow it, the rethrown error is not reported again, not even as a crash. If the error is going to end the app, report it with `logUnhandledException` instead of `logException`, not after it: whichever call sees the error object first claims it, and later calls for the same object do nothing.
+- An error object is claimed even when its report is dropped. `logException` before `launch` claims the object although the native SDK drops the report, so no later route reports that same object.
+- A primitive (a thrown string or number) cannot be remembered, so the same string logged twice produces two reports.
+
+### `AggregateError`
+
+A handled `AggregateError` is split: each of its first 10 inner errors becomes its own error report, and the aggregate itself is not reported. Inner errors already reported are skipped. An unhandled `AggregateError` (from `logUnhandledException` or a fatal error) stays one crash report.
+
+## What a report carries
+
+The exception is built from the JavaScript error, the same way on both platforms:
+
+- **Name and message.** For an `Error`, its `name` and `message`. A thrown string becomes the message, with the name `Error`. An object with a string `message` gives that message (and its `name`, when that is a string). Anything else is reported as `Non-Error thrown: `.
+- **Stack trace.** The error's own stack, up to 256 frames. A value that is not an `Error` has no stack of its own, so `logException` and `logUnhandledException` record the stack at the point you called them.
+- **Causes.** The `cause` chain, up to 10 levels deep.
+- **Component stack.** For a render error, the React component stack, as the innermost cause.
+
+The message is cut at 8192 characters and the name at 256; a cut value ends in `…`.
+
+## Testing crash reporting
+
+Two helpers check that reporting is wired up. Use them only in development and QA builds.
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// Throws an Error('Bugsee test JS crash') at the call site.
+Bugsee.testJsCrash();
+
+// Raises a native test crash, which ends the app.
+Bugsee.testNativeCrash();
+```
+
+- `testJsCrash()` throws a JavaScript `Error` where you call it. Call it from a button handler, where nothing catches it, so it reaches the global handler. In a development build, React Native also shows its error screen.
+- `testNativeCrash()` raises a native test crash: a Java `RuntimeException` on Android, an `NSException` on iOS. The report is sent at the next launch.
+
+On iOS, run both on a physical device; see [iOS Simulator](#native-crashes).
+
+## Report severity
+
+Crash reports get `IssueSeverity.Blocker` and error reports `IssueSeverity.High` by default, on both platforms. Change the defaults with `com.bugsee.option.reporting.defaults.crash-priority` and `com.bugsee.option.reporting.defaults.error-priority` (see [Default severities](/sdk/react_native/manual/bug-reporting#default-severities)), or set a severity on individual reports from a [report handler](/sdk/react_native/report-handler). `logException` has no severity option.
+
+## Related pages
+
+- [Error boundary](/sdk/react_native/error-boundary): report render errors and show a fallback.
+- [Report handler](/sdk/react_native/report-handler): add labels and attachments to crash and error reports.
+- [Symbolication](/sdk/react_native/symbolication/overview): readable stack traces in release builds.
+- [Configuration](/sdk/react_native/configuration#detection): the detection options.
diff --git a/docs/sdk/react_native/migration.mdx b/docs/sdk/react_native/migration.mdx
new file mode 100644
index 0000000..dea3766
--- /dev/null
+++ b/docs/sdk/react_native/migration.mdx
@@ -0,0 +1,666 @@
+---
+title: "Migrating from 6.x to 7.x"
+description: "Step-by-step guide for moving a React Native app from react-native-bugsee 6.x to @bugsee/react-native 7.x: packages, requirements, launch options, renamed and removed APIs, build changes and a checklist."
+sidebar_position: 25
+slug: "/sdk/react_native/migration"
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+:::note
+This guide compares `react-native-bugsee` 6.0.x with `@bugsee/react-native` `7.0.0-beta3`. If you are setting up a new project, start from [Installation](/sdk/react_native/installation) instead.
+:::
+
+This guide walks through every public-API change between the 6.x package (`react-native-bugsee`) and the 7.x package (`@bugsee/react-native`, plus `@bugsee/react-native-feedback` for the feedback chat).
+
+:::note[TL;DR]
+7.x is a new package, not an upgrade in place. It requires React Native 0.81 or later with the New Architecture and Hermes. The default export is still a `Bugsee` singleton and many method names carry over, but the options, the enums, the filters, the lifecycle events, the error boundary and the build integration all change, and the feedback chat moves to its own package. Expect code changes in every file that touches Bugsee.
+:::
+
+---
+
+## 1. Packages and requirements
+
+### 1.1 Replace the package
+
+Remove the 6.x package and add the 7.x one. Add the feedback package only if you show the feedback chat.
+
+```sh
+yarn remove react-native-bugsee
+yarn add @bugsee/react-native@beta
+yarn add @bugsee/react-native-feedback@beta # only if you use the feedback chat
+```
+
+| 6.x | 7.x |
+| --- | --- |
+| `react-native-bugsee` | `@bugsee/react-native` |
+| Feedback chat inside the main package | `@bugsee/react-native-feedback`, at the same version as `@bugsee/react-native` |
+| `bugsee-sourcemaps` (a dev dependency you installed for source-map uploads) | `@bugsee/cli`, a dependency of `@bugsee/react-native`, installed with it |
+| `import Bugsee from 'react-native-bugsee'` | `import Bugsee from '@bugsee/react-native'` |
+
+Then update every import. Types, enums, components and helpers that 6.x hung off the default export are **named exports** in 7.x:
+
+```ts
+import Bugsee, {
+ AndroidLaunchOptions,
+ BugseeSecure,
+ ErrorBoundary,
+ IOSLaunchOptions,
+ IssueSeverity,
+ LogLevel,
+ createDefaultLaunchOptions,
+} from '@bugsee/react-native';
+```
+
+### 1.2 Requirements
+
+| | 6.x | 7.x |
+| --- | --- | --- |
+| React Native | Not stated by the package | 0.81 or later, **New Architecture enabled** |
+| JavaScript engine | Not stated by the package | **Hermes**. JavaScriptCore is not supported. |
+| iOS | 12.0 or later | 15.0 or later (15.1 with CocoaPods, React Native's own floor) |
+| Android | API 21; AGP 8.6.0 or later, `compileSdkVersion` 35 | API 21 or later |
+| Expo | Prebuild, with your own native edits | Prebuild, with the package's [config plugin](/sdk/react_native/expo). Expo Go is not supported. |
+
+On the legacy architecture the 7.x package fails when it is imported. See [Overview](/sdk/react_native/overview#requirements).
+
+### 1.3 Native setup
+
+| | 6.x | 7.x |
+| --- | --- | --- |
+| iOS SDK | The `Bugsee` pod from CocoaPods trunk, or `Bugsee.xcframework` copied in by hand | Brought by the package: its `Package.swift` with React Native's Swift Package Manager integration (0.87 and later), or its podspec, which downloads and vendors the XCFramework during `pod install`. Remove a hand-copied `Bugsee.xcframework`. |
+| Android SDK | `com.bugsee:bugsee-android:+` (any version) | `com.bugsee:bugsee-android` 7.4.2, plus its NDK and OkHttp modules, pinned by the package |
+| Android Gradle plugin | Not needed | The Bugsee Gradle plugin (`com.bugsee.android.gradle`), for `fetch`/XHR network capture on Android and for the R8 mapping and native-symbol uploads. See [Symbolication: Android](/sdk/react_native/symbolication/android). |
+
+Without the Bugsee Gradle plugin, a 7.x Android app builds and runs, but records no `fetch` or `XMLHttpRequest` traffic. See [Installation](/sdk/react_native/installation#android).
+
+---
+
+## 2. Launching the SDK
+
+### 2.1 `launch`, `relaunch` and `stop` resolve to a result
+
+| 6.x | 7.x |
+| --- | --- |
+| `launch(appToken, options?): Promise` | `launch(token, options?): Promise`: `true` when the SDK started (or was already running; the options are then not applied), `false` when it declined (for example, a rejected token) |
+| `relaunch(options?): Promise` | `relaunch(options?): Promise` |
+| `stop(): Promise` | `stop(): Promise` |
+| `initialize()`: wire up JavaScript when native code launched the SDK | `attach()`: the same, for an SDK launched before JavaScript runs (from Android manifest meta-data, or by your native code) |
+| No token check | A missing, empty or blank token rejects with the code `E_TOKEN` |
+
+`launch` resolving does not mean capture has started: poll `getStatus()` or subscribe with `onStatusChange`. See [Lifecycle & status](/sdk/react_native/lifecycle).
+
+### 2.2 Wrap your root component
+
+7.x adds `Bugsee.wrap(App)`. Without it, reports carry no view hierarchy, and an uncaught render error is not reported at all, because on React Native 0.81 and later render errors do not reach the global error handler. See [Render errors](/sdk/react_native/manual/crash-error-reporting#render-errors).
+
+```ts title="index.js"
+AppRegistry.registerComponent(appName, () => Bugsee.wrap(App));
+```
+
+### 2.3 Launch options
+
+In 6.x you created `new Bugsee.IOSLaunchOptions()` or `new Bugsee.AndroidLaunchOptions()`. Each came **pre-filled with the 6.x package's own defaults**, and its properties wrote 6.x option names (`MaxRecordingTime`, `ShakeToReport`, …).
+
+In 7.x, `createDefaultLaunchOptions()` returns an `IOSLaunchOptions` or an `AndroidLaunchOptions` for the running platform. It is **empty**: an option you leave unset is not sent, and the native SDK applies its own default. Its accessors write the shared `com.bugsee.option.*` keys, and `setCustomOption` takes those keys too. Pass the object to `launch` as is, or pass a plain map of `com.bugsee.option.*` keys instead.
+
+
+
+
+```ts
+import { Platform } from 'react-native';
+import Bugsee from 'react-native-bugsee';
+
+const options =
+ Platform.OS === 'ios' ? new Bugsee.IOSLaunchOptions() : new Bugsee.AndroidLaunchOptions();
+options.maxRecordingTime = 120;
+options.shakeToReport = true;
+options.defaultBugPriority = Bugsee.Severity.High;
+
+Bugsee.launch(token, options);
+```
+
+
+
+
+```ts
+import Bugsee, { IssueSeverity, createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.duration = 120;
+options.setCustomOption('com.bugsee.option.reporting.triggers.shake', true);
+options.setCustomOption('com.bugsee.option.reporting.defaults.bug-priority', IssueSeverity.High);
+
+Bugsee.launch(token, options);
+```
+
+
+
+
+:::caution[Defaults change with the empty options object]
+Because 7.x sends only what you set, the native defaults apply where 6.x sent its own. These change without any code of yours changing:
+
+| Behavior | 6.x default (set by the 6.x package) | 7.x default (native) |
+| --- | --- | --- |
+| Shake to report (`com.bugsee.option.reporting.triggers.shake`) | Off | On |
+| Default bug severity (`com.bugsee.option.reporting.defaults.bug-priority`) | `Low` | `High` |
+| Screenshot to report on iOS (`com.bugsee.option.reporting.triggers.screenshot`) | On | Off |
+| Disk space for pending reports on Android (`maxDataSize`) | 50 MB | 150 MB |
+| Android video mode (`videoMode`) | `V3` | `V2` |
+| Exit detection, including ANRs on Android (`com.bugsee.option.detect.exit`) | Off (`handleAnr`, iOS `killDetection`) | On |
+| Android native (NDK) crash reporting | Off (`ndkCrashReport`) | Always included |
+| Early-crash detection on iOS (`com.bugsee.option.detect.early-crash`) | Off | On |
+| Adaptive video capture on iOS (`com.bugsee.option.capture.video.adaptive`) | Off | On: frames are skipped while nothing on screen changes |
+| iOS crash handler (`com.bugsee.option.capture.crash-handler-type`) | BSD signal handlers | `MachAndBSD`: a Mach exception handler as well as the BSD signal handlers |
+
+Check the defaults on [Configuration](/sdk/react_native/configuration) for every option you relied on, and set the ones you need explicitly.
+:::
+
+In `7.0.0-beta1`, `launch` and `relaunch` took only the plain map, so you passed `BugseeLaunchOptions.serialize(options)`. From `7.0.0-beta2` they take the options object as is; `serialize` still returns the same map if you need it.
+
+---
+
+## 3. Option mapping
+
+In the tables below, a 7.x accessor is a property of the options object; a key without an accessor is set with `options.setCustomOption(key, value)` or in a plain map. [Configuration](/sdk/react_native/configuration) has every key with its type and default.
+
+### 3.1 Options on both platforms
+
+| 6.x property (6.x option name) | 7.x accessor or key |
+| --- | --- |
+| `maxRecordingTime` (`MaxRecordingTime`) | `duration` (`com.bugsee.option.config.duration`) |
+| `videoEnabled` (`VideoEnabled`) | `captureVideo` (`com.bugsee.option.capture.video`) |
+| `screenshotEnabled` (`ScreenshotEnabled`) | `com.bugsee.option.capture.screenshot` |
+| `captureLogs` (`CaptureLogs`) | `captureLogs` (`com.bugsee.option.capture.logs`) |
+| `monitorNetwork` (`MonitorNetwork`) | `captureNetwork` (`com.bugsee.option.capture.network`) |
+| `maxNetworkBodySize` | `com.bugsee.option.capture.network.body-size-limit` |
+| `crashReport` (`CrashReport`) | `detectAndReportCrash` (`com.bugsee.option.detect.crash`) |
+| `handleRejections` (JavaScript only, off unless set) | No option. Unhandled promise rejections are always reported after `launch`, as errors; `detectAndReportCrash: false` turns that off with the other automatic reporting. See [Unhandled promise rejections](/sdk/react_native/manual/crash-error-reporting#unhandled-promise-rejections). |
+| `wifiOnlyUpload` (`WifiOnlyUpload`) | `wifiOnlyUpload` (`com.bugsee.option.config.wifi-only-upload`) |
+| `maxDataSize` (`MaxDataSize`) | `maxDataSize` (`com.bugsee.option.config.max-data-size`) |
+| `shakeToReport` (`ShakeToReport`) | `com.bugsee.option.reporting.triggers.shake` |
+| `screenshotToReport` (Android `ScreenshotToTrigger`, iOS `ScreenshotToReport`) | `com.bugsee.option.reporting.triggers.screenshot` |
+| `reportPrioritySelector` (`BugseeReportPrioritySelector`) | `com.bugsee.option.reporting.ui.priority-selector-enabled` |
+| `reportSummaryRequired` (`ReportSummaryRequired`) | `com.bugsee.option.reporting.ui.summary-required` |
+| `reportDescriptionRequired` (`ReportDescriptionRequired`) | `com.bugsee.option.reporting.ui.description-required` |
+| `reportEmailRequired` (`ReportEmailRequired`) | `com.bugsee.option.reporting.ui.email-required` |
+| `defaultCrashPriority` (`BugseeDefaultCrashPriority`) | `com.bugsee.option.reporting.defaults.crash-priority` |
+| `defaultBugPriority` (`BugseeDefaultBugPriority`) | `com.bugsee.option.reporting.defaults.bug-priority` |
+| _(no 6.x option)_ | `com.bugsee.option.reporting.defaults.error-priority` |
+| `frameRate` (`FrameRate`) | `com.bugsee.option.capture.video.frame-rate` |
+| `minFrameRate`, `maxFrameRate` (`MinFrameRate`, `MaxFrameRate`; sent on both platforms) | iOS only: `com.bugsee.option.capture.video.min-frame-rate`, `com.bugsee.option.capture.video.max-frame-rate` |
+| `captureDeviceAndNetworkNames` (`CaptureDeviceAndNetworkNames`; sent on both platforms) | iOS only: `com.bugsee.option.capture.device-network-names` |
+| `setCustomOption(key, value)` with a 6.x option name | `setCustomOption(key, value)` with a `com.bugsee.option.*` key |
+
+### 3.2 Android options
+
+| 6.x property (6.x option name) | 7.x accessor or key |
+| --- | --- |
+| `notificationBarTrigger` (`NotificationBarTrigger`) | `triggerByNotification` (`com.bugsee.option.reporting.triggers.notification-bar`) |
+| `videoMode` (`VideoMode`: `None`, `V1`, `V2`, `V3`) | `videoMode` (`com.bugsee.option.capture.video.mode`: `None`, `V1`, `V2`, `Fullscreen`, `DirectBuffers`). `V3` no longer exists. |
+| `videoQuality` (`VideoQuality`) | `com.bugsee.option.capture.video.quality` |
+| `fallbackVideoMode` (`FallbackVideoMode`) | No 7.x option. |
+| `serviceMode` (`ServiceMode`) | No 7.x option. |
+| `ndkCrashReport` (`NdkCrashReport`) | No option: the package includes NDK crash reporting (`bugsee-android-ndk`). With Expo, the config plugin's `nativeCrashReporting: false` leaves it out. A bare app can do what that option writes: exclude the module in `android/app/build.gradle` with `configurations.configureEach { exclude group: 'com.bugsee', module: 'bugsee-android-ndk' }`, and declare no `bugsee-android-ndk` dependency of its own. |
+| `handleAnr` (`HandleAnr`) | No option by that name. ANR exits are reported through exit detection: `com.bugsee.option.detect.exit`, and on Android `com.bugsee.option.detect.exit.not_responding` (and `com.bugsee.option.detect.exit.not_responding.as_crash` to report them as crashes); see [Platform-only keys](/sdk/react_native/configuration#platform-only-keys). |
+
+### 3.3 iOS options
+
+| 6.x property (6.x option name) | 7.x accessor or key |
+| --- | --- |
+| `monitorDiskSpace` (`MonitorDiskSpace`) | `captureDiskSpace` (`com.bugsee.option.capture.disk-space`) |
+| `captureAVPlayer` (`CaptureAVPlayer`) | `captureAVPlayer` (`com.bugsee.option.capture.avplayer`) |
+| `videoScale` (`VideoScale`) | `com.bugsee.option.capture.video.scale` (both platforms in 7.x) |
+| `monitorBluetoothStatus` (`MonitorBluetoothStatus`) | `com.bugsee.option.capture.bluetooth-status` |
+| `killDetection` (`BugseeKillDetectionKey`) | No option by that name. Exit detection is `com.bugsee.option.detect.exit`. |
+
+### 3.4 New in 7.x
+
+Options with no 6.x counterpart include `captureLogsLevel`, `captureBreadcrumbs`, `detectAndReportHang`, `endpoint`, Android's `logsUseAllSources`, `detectAndReportExitLowMemory`, `maxPendingReports` and `maxPendingReportAge`, iOS's `crashHandlerType` and `crashSignals`, and keys such as `com.bugsee.option.detect.http-errors`, `com.bugsee.option.capture.network.default-sanitizer` and `com.bugsee.option.performance.enabled`. See [Configuration](/sdk/react_native/configuration).
+
+---
+
+## 4. Enums
+
+6.x exposed its enums as properties of the default export (`Bugsee.LogLevel`, `Bugsee.Severity`, …). 7.x exports them by name.
+
+| 6.x | 7.x | Changes |
+| --- | --- | --- |
+| `Bugsee.Severity` (`Low` 1 … `Blocker` 5) | `IssueSeverity` | `Low` is now `VeryLow`; the values 1 to 5 are unchanged. |
+| `Bugsee.LogLevel` (`None` 0, `Error` 1 … `Verbose` 5) | `LogLevel` | `None` is gone; `Error` 1 to `Verbose` 5 are unchanged. |
+| `Bugsee.VideoMode` (`None`, `V1`, `V2`, `V3`) | `VideoMode` | `V3` is gone; `Fullscreen` (20) and `DirectBuffers` (21) are new. Android only. |
+| `Bugsee.VideoQuality` | `VideoQuality` | Unchanged values. |
+| `FrameRate` (types only) | `FrameRate` | Exported as a value. |
+| `Bugsee.LifecycleEventsTypes` (numbers) | Event names (strings); see [§8](#8-lifecycle-events) | |
+| _(none)_ | `CrashHandlerType`, `Status`, `SpanStatus`, and the error-code enums `ReportErrorCode`, `AttributeErrorCode` and `SpanErrorCode` | New. |
+
+---
+
+## 5. Method changes
+
+### 5.1 Reporting
+
+| 6.x | 7.x |
+| --- | --- |
+| `showReportDialog(summary?, description?, severity?)` | `showReportDialog(summary?, description?, severity?, labels?)` |
+| `upload(summary, description?, severity?, labels?, includeVideo = true)` | `upload(summary, description, severity?, labels?)`. `description` is required (an empty string is fine). There is no `includeVideo`: a fifth argument throws `TypeError`. |
+| `logException(exception, { domain, labels, includeVideo, mergingRules })` | `logException(error, { domain })`. Any other key throws `TypeError`; see [§6.1](#61-logexception-takes-only-a-domain). |
+| `testNativeCrash()`, `testJsCrash()` | Unchanged. |
+| _(none)_ | `createReport()`, `setReportHandler(handler)`, `logUnhandledException(error)`, `notify(…)` |
+
+See [Bug reporting](/sdk/react_native/manual/bug-reporting) and [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting).
+
+### 5.2 Data capture
+
+| 6.x | 7.x |
+| --- | --- |
+| `log(text, level?)` | `log(message, level = LogLevel.Info, requiresFiltering = false)`. Dropped before `launch`. See [Writing your own lines](/sdk/react_native/logs#writing-your-own-lines). |
+| `event(name, params?)` | `event(name, params?)`. Names and parameters are validated, and invalid input throws; see [Custom events & traces](/sdk/react_native/events-and-traces). |
+| `trace(name, value)` | `trace(name, value)`, validated the same way. |
+| `setAttribute(name, value): void` | `setAttribute(name, value): Promise`, which rejects with a `BugseeAttributeError` for invalid input |
+| `getAttribute(name)`, `clearAttribute(name)`, `clearAllAttributes()` | The same names, all returning promises. `getAllAttributes()` is new. See [User & session data](/sdk/react_native/user-session-data). |
+| `setEmail(email)`, `getEmail()`, `clearEmail()` | Removed. Use `setUserIdentifier(id)`, `getUserIdentifier()`, `clearUserIdentifier()` to tie reports to a user; the feedback chat takes an identifier that contains `@` as the user's address. See [User identity](/sdk/react_native/user-session-data#user-identity). |
+| `setAppVersion(version, build)`, `getAppVersion()`, `getAppBuild()` | Removed. 6.x needed the version to match uploaded source maps; 7.x matches them by debug ID. See [§11](#11-build-and-symbolication). |
+| `captureViewHierarchy()` | Unchanged; the view hierarchy also needs `Bugsee.wrap(App)`. |
+| _(none)_ | `addBreadcrumb`, `setBreadcrumbFilter`, `addNetworkEvent`, `startTransaction`, `startSpan`, `getActiveSpan` |
+
+### 5.3 Filters and handlers
+
+| 6.x | 7.x |
+| --- | --- |
+| `setLogFilter(async (event: LogEvent) => LogEvent)` | `setLogFilter((line: string) => string \| null)`; see [§7](#7-filters) |
+| `setNetworkFilter(async (event: NetEvent) => NetEvent)` | `setNetworkFilter((event: NetworkFilterEvent) => NetworkFilterEvent \| null)`; see [§7](#7-filters) |
+| `setLifecycleEventHandler(callback)` | `onLifecycleEvent(listener)`, which returns a subscription; see [§8](#8-lifecycle-events) |
+| `setAttachmentsHandler(handler)` | `setReportHandler({ onAfterReportCreated })`; see [§9](#9-attachments-and-the-report-handler) |
+| `setNewFeedbackMessageCallback(callback)` | `setListener({ onNewMessagesReceived })` from `@bugsee/react-native-feedback`; see [§10](#10-feedback) |
+
+### 5.4 Privacy and lifecycle
+
+| 6.x | 7.x |
+| --- | --- |
+| `toggleProtected(component, isProtected)` | ``; see [§5.5](#55-hiding-views) |
+| `addSecureRect(x, y, width, height)`, `removeSecureRect(…)`, `removeAllSecureRects()` | `setSecureRectangles(rectangles, display?)`, which replaces the whole list; `[]` clears it |
+| `getAllSecureRects()` | Removed. |
+| `pause()`, `resume()` | `startBlackout()`, `endBlackout()`, `isBlackout()`. A blackout suppresses the video, the screenshot, touches and the view hierarchy; logs and network events keep recording. See [Blackout](/sdk/react_native/privacy/video#blackout). |
+| `setKeyboardVisibility(isVisible)` | Removed. |
+| `deleteCollectedDataOnDevice()` | `deleteCollectedDataOnDevice(includingIntermediate)`; the SDK must be stopped first. See [Cleanup](/sdk/react_native/privacy/cleanup). |
+| `initialize()` | `attach()` |
+| _(none)_ | `getStatus()`, `onStatusChange(listener)`, `getLaunchOptions()`, `wrap(App)` |
+
+### 5.5 Hiding views
+
+6.x masked a component by its node handle. 7.x masks what you wrap, and unmasks when the wrapper unmounts.
+
+
+
+
+```tsx
+import { useEffect, useRef } from 'react';
+import { Text } from 'react-native';
+import Bugsee from 'react-native-bugsee';
+
+function AccountNumber({ value }: { value: string }) {
+ const ref = useRef(null);
+ useEffect(() => {
+ Bugsee.toggleProtected(ref.current, true);
+ return () => Bugsee.toggleProtected(ref.current, false);
+ }, []);
+ return {value} ;
+}
+```
+
+
+
+
+```tsx
+import { Text } from 'react-native';
+import { BugseeSecure } from '@bugsee/react-native';
+
+function AccountNumber({ value }: { value: string }) {
+ return (
+
+ {value}
+
+ );
+}
+```
+
+
+
+
+See [Privacy: Video](/sdk/react_native/privacy/video).
+
+---
+
+## 6. Exceptions and the error boundary
+
+### 6.1 `logException` takes only a domain
+
+The 6.x options `labels`, `includeVideo` and `mergingRules.skipFrames` are gone. 7.x accepts only `domain`: the 7.x native SDKs take no per-call labels or video switch, and `skipFrames` is not exposed in this beta. Passing any other key throws `TypeError: ExceptionOptions has unknown key "…"` before anything is sent.
+
+- **Labels**: set them from a [report handler](/sdk/react_native/report-handler). It has no per-call context, so the labels land on every report it handles.
+- **`includeVideo`**: no replacement. Neither SDK can leave the video out of one report.
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: (report) => report.setLabels(['checkout']),
+});
+
+try {
+ submitOrder();
+} catch (error) {
+ Bugsee.logException(error, { domain: 'checkout' });
+}
+```
+
+### 6.2 Automatic reporting
+
+- **Unhandled promise rejections** were reported in 6.x only with `handleRejections` set. 7.x reports them after every `launch`, as errors.
+- **Uncaught render errors** need `Bugsee.wrap(App)` in 7.x; see [§2.2](#22-wrap-your-root-component).
+- `detectAndReportCrash: false` turns off the automatic reporting; `logException` and `` still report.
+
+See [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting).
+
+### 6.3 ``
+
+| 6.x | 7.x |
+| --- | --- |
+| `Bugsee.ErrorBoundary` | `ErrorBoundary`, a named export |
+| `children` can be a function that returns the tree | `children` is a `ReactNode`. The function form is gone: render the tree directly. |
+| Fallback function receives `{ error, componentStack, resetErrorBoundary }` | Fallback function receives `{ error, componentStack, resetError }`, with `error` typed `unknown` |
+| `onError(error: Error, componentStack)` | `onError(error: unknown, componentStack)`: the thrown value need not be an `Error` |
+| `onReset(error, componentStack)` | `onReset(error: unknown, componentStack)`, otherwise unchanged |
+| _(none)_ | `options` prop: `{ domain }` for the report |
+
+
+
+
+```tsx
+import { Button } from 'react-native';
+import Bugsee from 'react-native-bugsee';
+
+ }
+>
+ {() => }
+
+```
+
+
+
+
+```tsx
+import { Button } from 'react-native';
+import { ErrorBoundary } from '@bugsee/react-native';
+
+ }>
+
+
+```
+
+
+
+
+See [Error boundary](/sdk/react_native/error-boundary).
+
+---
+
+## 7. Filters
+
+In 6.x a filter was an async callback that received an event object and returned it. In 7.x the native SDK calls the filter for each item it records and waits for the answer, so the shapes and rules change.
+
+| | 6.x | 7.x |
+| --- | --- | --- |
+| Log filter receives | `LogEvent`: `{ text, level, timestamp? }` | The line's text, a string. Only the text can change. |
+| Log filter returns | The event, or nothing to drop the line | A string to keep or replace the line, `null` to drop it |
+| Network filter receives | `NetEvent`: `{ type, method, url, redirected_from?, body?, headers?, error? }` | `NetworkFilterEvent`, with per-platform writable fields |
+| Network filter returns | The event | The event (start from a spread of the one you received), or `null` to drop it. Leaving out a writable field drops the event. |
+
+In 7.x, a callback that throws, or a promise that rejects, drops the item. `setLogFilter()` or `setNetworkFilter()` with no argument, or with `null`, removes the filter.
+
+
+
+
+```ts
+import Bugsee from 'react-native-bugsee';
+
+Bugsee.setLogFilter(async (event) => ({
+ ...event,
+ text: event.text.replace(/token=\S+/g, 'token='),
+}));
+```
+
+
+
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+Bugsee.setLogFilter((line) => line.replace(/token=\S+/g, 'token='));
+```
+
+
+
+
+Install filters **before** `Bugsee.launch`. Details, deadlines and reload behavior: [Console logs](/sdk/react_native/logs#filtering-log-lines), [Network events](/sdk/react_native/network#filtering-network-events) and the [Privacy](/sdk/react_native/privacy/overview) pages.
+
+6.x also recorded `WebSocket` traffic through a JavaScript patch. 7.x has no such patch.
+
+---
+
+## 8. Lifecycle events
+
+`setLifecycleEventHandler(callback)` called you with a number. `onLifecycleEvent(listener)` calls you with an object, `{ name, reportId? }`, and returns a subscription with `remove()`.
+
+| 6.x `LifecycleEventsTypes` | 7.x `event.name` |
+| --- | --- |
+| `Launched` (0) | `'Launched'` (`'Launching'` is new) |
+| `Started` (1) | No equivalent |
+| `Stopped` (2) | `'Stopped'` (`'Stopping'` is new) |
+| `Resumed` (3), `Paused` (4) | No equivalent. `'BlackoutStarted'` and `'BlackoutEnded'` report `startBlackout` and `endBlackout`. |
+| `RelaunchedAfterCrash` (5) | `'RelaunchedAfterCrash'` |
+| `BeforeReportShown` (6), `AfterReportShown` (7) | `'BeforeReportShown'`, `'AfterReportShown'` |
+| `BeforeReportUploaded` (8), `AfterReportUploaded` (9) | `'BeforeReportUploaded'`, `'AfterReportUploaded'`, with `reportId` |
+| `BeforeFeedbackShown` (10), `AfterFeedbackShown` (11) | No equivalent |
+| `BeforeReportAssembled` (12), `AfterReportAssembled` (13): in the 6.x TypeScript enum only, not in `Bugsee.LifecycleEventsTypes` | `'BeforeReportAssembled'`, `'AfterReportAssembled'`, with `reportId` |
+| _(none)_ | `'ReportAssemblyFailed'`, `'ReportUploadFailedWithFutureRetry'`, `'ReportUploadFailed'` |
+
+
+
+
+```ts
+import Bugsee from 'react-native-bugsee';
+
+Bugsee.setLifecycleEventHandler(async (eventType) => {
+ if (eventType === Bugsee.LifecycleEventsTypes.RelaunchedAfterCrash) {
+ showCrashApology();
+ }
+});
+```
+
+
+
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const subscription = Bugsee.onLifecycleEvent((event) => {
+ if (event.name === 'RelaunchedAfterCrash') {
+ showCrashApology();
+ }
+});
+// subscription.remove() to stop listening
+```
+
+
+
+
+For the SDK's state, use `getStatus()` and `onStatusChange(listener)` instead of tracking events. See [Lifecycle & status](/sdk/react_native/lifecycle).
+
+---
+
+## 9. Attachments and the report handler
+
+6.x asked an attachments handler for a list of attachments while it bundled a report. 7.x hands the report itself to a report handler, which can read and change it and add attachments.
+
+
+
+
+```ts
+import Bugsee from 'react-native-bugsee';
+
+Bugsee.setAttachmentsHandler(async (report) => {
+ if (report.type !== 'crash') {
+ return [];
+ }
+ return [{ name: 'state', filename: 'state.json', data: JSON.stringify(appState()) }];
+});
+```
+
+
+
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// React Native's default TypeScript config has no DOM types.
+declare function btoa(data: string): string;
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ if (report.type !== 'crash') {
+ return;
+ }
+ const names = await report.getAttachmentNames();
+ if (!names.includes('state.json')) {
+ await report.addDataAttachment(btoa(JSON.stringify(appState())), {
+ name: 'state.json',
+ mimeType: 'application/json',
+ });
+ }
+ },
+});
+```
+
+
+
+
+`btoa` encodes only Latin-1 text and throws on anything else, such as JSON with emoji or non-Latin text; encode such text to bytes first, or use a base64 library. `onAfterReportCreated` can run more than once for a report, so the example checks for the attachment before adding it. Call `setReportHandler` **before** `launch`, or it misses the reports launch recovers. See [Report handler](/sdk/react_native/report-handler).
+
+---
+
+## 10. Feedback
+
+The feedback chat moved to `@bugsee/react-native-feedback`, as plain functions. Call them after `Bugsee.launch` has resolved.
+
+| 6.x (`react-native-bugsee`) | 7.x (`@bugsee/react-native-feedback`) |
+| --- | --- |
+| `Bugsee.showFeedbackUI()` | `showFeedbackUI()` |
+| `Bugsee.setDefaultFeedbackGreeting(message)` | `setGreeting(greeting)`; `null` clears it |
+| `Bugsee.setNewFeedbackMessageCallback(async ({ messages }) => …)` | `setListener({ onNewMessagesReceived(messages) { … }, onNewMessageSent(message) { … } })`; `null` removes it |
+| `Bugsee.appearance.AndroidFeedbackAppearance`, `Bugsee.appearance.IOSFeedbackAppearance` | `appearance` from `@bugsee/react-native-feedback` |
+
+```ts
+import { setGreeting, setListener, showFeedbackUI } from '@bugsee/react-native-feedback';
+
+setGreeting('How can we help?');
+setListener({
+ onNewMessagesReceived(messages) {
+ showBadge(messages.length);
+ },
+});
+showFeedbackUI();
+```
+
+See [Feedback](/sdk/react_native/feedback).
+
+### Report UI appearance
+
+6.x split the report colors by platform: `Bugsee.appearance.AndroidReportAppearance` and `Bugsee.appearance.IOSReportAppearance`. 7.x has one cross-platform surface, `Bugsee.appearance`. Setting a color that exists on one platform only throws on the other. See [Appearance](/sdk/react_native/appearance).
+
+---
+
+## 11. Build and symbolication
+
+7.x replaces the 6.x source-map tooling and matches JavaScript frames by **debug ID**, an ID derived from the bundle's content and written into the bundle and its map at build time. The version and build number you uploaded with no longer have to match a value you set at runtime, which is why `setAppVersion` is gone.
+
+| | 6.x | 7.x |
+| --- | --- | --- |
+| Upload tool | `bugsee-sourcemaps`, installed by you | `@bugsee/cli`, installed with the package |
+| Android source maps | `apply from: "../../node_modules/react-native-bugsee/bugsee.gradle"` | `react.hermesCommand` pointed at the package's `hermesc-preserve-js` launcher, and `apply from: …/scripts/bugsee-sourcemaps.gradle` |
+| Android token for uploads | `app.token` in `android/bugsee.properties` (or `bugseeConfig.appToken`, or `BUGSEE_APP_TOKEN`) | `app_token` in `android/bugsee.properties` (or `BUGSEE_APP_TOKEN`) |
+| Per-flavor tokens | `project.ext.bugseeConfig = [flavorAware: true]` with `android/bugsee-.properties` | No equivalent: the hook reads only the root `android/bugsee.properties` and the environment. Export a different `BUGSEE_APP_TOKEN` per build job instead. |
+| Android R8 mapping and native symbols | Not handled by the package | The Bugsee Gradle plugin, with `plugin.ndk.enabled=true` for native symbols |
+| iOS source maps | The bundle phase runs `react-native-bugsee/scripts/build-wrap.sh` around React Native's script, with `BUGSEE_PROPERTIES` | The bundle phase runs `@bugsee/react-native/scripts/bugsee-xcode.sh`, with `BUGSEE_APP_TOKEN` exported in `ios/.xcode.env.local` |
+| iOS dSYMs | The native SDK's `BugseeAgent` post-action | An Archive post-action that runs `bugsee-cli xcode post-action` |
+| Expo | No config plugin | The [config plugin](/sdk/react_native/expo) writes all of the above |
+
+Remove the 6.x lines (`bugsee.gradle`, `project.ext.bugseeConfig`, per-flavor `bugsee-.properties` files, `build-wrap.sh`, `BUGSEE_PROPERTIES`, the `bugsee-sourcemaps` dependency, a `BugseeAgent` post-action) and follow [Symbolication](/sdk/react_native/symbolication/overview).
+
+---
+
+## 12. New in 7.x
+
+| Feature | Page |
+| --- | --- |
+| `Bugsee.wrap(App)`: view hierarchy and uncaught render errors | [Installation](/sdk/react_native/installation#4-launch-bugsee) |
+| Status: `getStatus()`, `onStatusChange()` | [Lifecycle & status](/sdk/react_native/lifecycle) |
+| Breadcrumbs: `addBreadcrumb()`, `setBreadcrumbFilter()` | [Breadcrumbs](/sdk/react_native/breadcrumbs) |
+| Custom network events: `addNetworkEvent()` | [Network events](/sdk/react_native/network) |
+| Report handler and created reports: `setReportHandler()`, `createReport()` | [Report handler](/sdk/react_native/report-handler), [Bug reporting](/sdk/react_native/manual/bug-reporting) |
+| `logUnhandledException()` | [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting) |
+| Performance monitoring: transactions and spans | [Performance monitoring](/sdk/react_native/performance) |
+| Notification relay: `notify()` | [Notification relay](/sdk/react_native/notification-relay) |
+| User identity and `getAllAttributes()` | [User & session data](/sdk/react_native/user-session-data) |
+| ``, `setSecureRectangles()`, blackout | [Privacy: Video](/sdk/react_native/privacy/video) |
+| Breadcrumb filter and network redaction | [Privacy](/sdk/react_native/privacy/overview) |
+| One camelCase report appearance surface | [Appearance](/sdk/react_native/appearance) |
+| Expo config plugin | [Expo](/sdk/react_native/expo) |
+| Source maps with debug IDs, Android mapping and native symbols, iOS dSYMs | [Symbolication](/sdk/react_native/symbolication/overview) |
+
+---
+
+## 13. Known beta limitations
+
+These are documented on the pages linked:
+
+- The iOS Simulator produces no crash reports; test crash reporting on a device. See [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting#native-crashes).
+- On Android, `fetch` and `XMLHttpRequest` are recorded only with the Bugsee Gradle plugin applied. See [Installation](/sdk/react_native/installation#android).
+- Under Android auto-launch with `attach()`, reports lack the JavaScript details until a `relaunch`, and launch options from JavaScript are not applied. See [Attach to a running SDK](/sdk/react_native/lifecycle#attach-to-a-running-sdk).
+- After a JavaScript reload, filters stay on while nothing in the new runtime answers them: install your filters first thing in your startup code. See the "Reloads" sections of [Console logs](/sdk/react_native/logs#reloads), [Network events](/sdk/react_native/network#reloads) and [Breadcrumbs](/sdk/react_native/breadcrumbs#reloads).
+- On Android, `captureLogsLevel` applies only to lines read from logcat, not to `console.*` lines or `Bugsee.log`. See [Which lines the level applies to](/sdk/react_native/logs#which-lines-the-level-applies-to).
+- `com.bugsee.option.capture.logs.oslog` is accepted and ignored by the iOS SDK in this beta. See [Platform-only keys](/sdk/react_native/configuration#platform-only-keys).
+- Performance data travels with reports; the standalone performance upload is not active. See [Performance monitoring](/sdk/react_native/performance).
+- One created report at a time, with no call to discard it. See [One created report at a time](/sdk/react_native/manual/bug-reporting#one-created-report-at-a-time).
+- `deleteCollectedDataOnDevice` keeps finished reports waiting for upload. See [Cleanup](/sdk/react_native/privacy/cleanup).
+- On iOS, most feedback chat colors have no effect. See [Feedback](/sdk/react_native/feedback#appearance).
+- In 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) the package's shell scripts are published without the executable bit, so the Android Release bundle task (bare and Expo) and the bare iOS bundle phase fail with "Permission denied" until you `chmod +x node_modules/@bugsee/react-native/scripts/*.sh` or run the iOS script through `/bin/bash`. See [Symbolication: Android](/sdk/react_native/symbolication/android#1-javascript-source-maps) and [Symbolication: iOS](/sdk/react_native/symbolication/ios#1-the-bundle-phase-javascript-source-maps).
+
+---
+
+## 14. Migration checklist
+
+1. **Swap the packages.** Remove `react-native-bugsee` and `bugsee-sourcemaps`; add `@bugsee/react-native@beta` (and `@bugsee/react-native-feedback@beta` if you use the chat). Check React Native 0.81+, the New Architecture and Hermes.
+2. **Clean the native projects.** Remove a hand-copied `Bugsee.xcframework` and the 6.x build lines; run `pod install`.
+3. **Fix the imports.** Default export from `@bugsee/react-native`; enums, `ErrorBoundary`, `BugseeSecure` and the options classes as named exports.
+4. **Rewrite the launch.** `createDefaultLaunchOptions()`, the [option mapping](#3-option-mapping), explicit values for every default you relied on, and `Bugsee.wrap(App)` at registration. Replace `initialize()` with `attach()`.
+5. **Install handlers before `launch`**: filters, the report handler, and your lifecycle subscription.
+6. **Port each API** with the [method tables](#5-method-changes): `logException` options, `upload` arguments, attributes as promises, `setEmail`, secure views, `pause`/`resume`, `deleteCollectedDataOnDevice`.
+7. **Port the error boundary, filters, lifecycle handler and attachments handler** ([§6](#6-exceptions-and-the-error-boundary) to [§9](#9-attachments-and-the-report-handler)).
+8. **Move the feedback calls** to `@bugsee/react-native-feedback`.
+9. **Set up symbolication**: the Expo config plugin, or the Android and iOS build edits in [Symbolication](/sdk/react_native/symbolication/overview), including the Bugsee Gradle plugin for Android network capture.
+10. **Verify** on a device, in a Release build: a bug report, a test crash with readable frames, network events on both platforms. See [Installation](/sdk/react_native/installation#5-verify).
+
+## Related pages
+
+- [Overview](/sdk/react_native/overview): what 7.x records and its requirements.
+- [Installation](/sdk/react_native/installation): a fresh 7.x setup.
+- [Release notes](/sdk/react_native/release-notes): what each 7.x beta changed.
+- [6.x documentation](/sdk/react_native/v6/installation): the stable release.
diff --git a/docs/sdk/react_native/network.mdx b/docs/sdk/react_native/network.mdx
new file mode 100644
index 0000000..069a5a9
--- /dev/null
+++ b/docs/sdk/react_native/network.mdx
@@ -0,0 +1,279 @@
+---
+title: "Network events"
+description: "How Bugsee React Native SDK 7.x records network traffic on iOS and Android, how to add events from other stacks with addNetworkEvent, and how to filter events with setNetworkFilter."
+sidebar_position: 7
+slug: "/sdk/react_native/network"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Bugsee records the HTTP requests your app makes, with their headers, bodies and response codes, and shows them on the report timeline next to the video and logs. The recording happens in native code, so `fetch` and `XMLHttpRequest` are not patched in JavaScript.
+
+## Automatic capture
+
+React Native sends `fetch` and `XMLHttpRequest` requests through the platform's networking stack (`NSURLSession` on iOS, OkHttp on Android), where the SDK records them.
+
+| Platform | Setup |
+| --- | --- |
+| iOS | None beyond [installation](/sdk/react_native/installation#ios). |
+| Android | The **Bugsee Gradle plugin** must be applied; see [Installation: Android](/sdk/react_native/installation#android). |
+
+:::warning[Android needs the Gradle plugin]
+Without the Bugsee Gradle plugin, `fetch` and `XMLHttpRequest` requests are **not recorded on Android**: the plugin is what lets the SDK record OkHttp traffic. The [Expo config plugin](/sdk/react_native/expo) applies the Gradle plugin for you.
+:::
+
+Requests that native code makes through the same stacks (`NSURLSession` on iOS, OkHttp on Android) are recorded the same way. Traffic from any other stack is not recorded; add it yourself with [`addNetworkEvent`](#recording-custom-network-events).
+
+Network events keep recording during a [blackout](/sdk/react_native/lifecycle#blackout).
+
+### WebSocket traffic
+
+The package has no JavaScript patch for `WebSocket`. Whether a React Native `WebSocket` is recorded:
+
+- **iOS**: yes, as WebSocket events (the connection, its messages and its failures), which your [network filter](#filtering-network-events) sees with `type: 'websocket'`, while `com.bugsee.option.capture.network` and the iOS-only `com.bugsee.option.capture.websocket` are on. Both are on by default; set `com.bugsee.option.capture.websocket` to `false` to leave WebSocket traffic out. This has not been verified on a device in this beta.
+- **Android**: not verified in this beta. There is no `capture.websocket` option on Android.
+
+## Capture options
+
+These launch options control network capture. Set them on the options object or in a plain map; see [Configuration](/sdk/react_native/configuration#other-shared-keys) for the full tables.
+
+| Option | Key | Default | Description |
+| --- | --- | --- | --- |
+| `captureNetwork` | `com.bugsee.option.capture.network` | `true` | Record network requests and responses. |
+| (no accessor) | `com.bugsee.option.capture.network.body-size-limit` | `20480` | Largest request or response body captured, in bytes. |
+| (no accessor) | `com.bugsee.option.capture.network.body-without-type` | `false` | Also keep bodies that declare no content type. |
+| (no accessor) | `com.bugsee.option.capture.network.on-launch` | `false` | Start network capture during `launch` instead of when capture starts, so startup requests are not missed. |
+| (no accessor) | `com.bugsee.option.capture.network.default-sanitizer` | `true` | Redact known sensitive keys in URLs, headers and JSON bodies. How it combines with a filter differs per platform; see [Filters and the built-in redaction](#filters-and-the-built-in-redaction). |
+| (no accessor) | `com.bugsee.option.detect.http-errors` | `false` | Turn HTTP 5xx responses into error reports. |
+
+Both native SDKs register these defaults. Read the values in effect with [`Bugsee.getLaunchOptions()`](/sdk/react_native/configuration#reading-the-effective-options).
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.captureNetwork = true;
+options.setCustomOption('com.bugsee.option.capture.network.body-size-limit', 10240);
+options.setCustomOption('com.bugsee.option.capture.network.on-launch', true);
+
+Bugsee.launch('', options);
+```
+
+## Filtering network events
+
+`Bugsee.setNetworkFilter(callback)` installs a filter that sees each network event before it is recorded. Return the event (changed or not) to keep it, or `null` to drop it:
+
+```ts
+import Bugsee, { type NetworkFilterEvent } from '@bugsee/react-native';
+
+function redactAuthorization(headers: Record): Record {
+ const out: Record = {};
+ for (const [name, value] of Object.entries(headers)) {
+ out[name] = name.toLowerCase() === 'authorization' ? '***' : value;
+ }
+ return out;
+}
+
+Bugsee.setNetworkFilter((event: NetworkFilterEvent) => {
+ // Drop health checks entirely
+ if (event.url?.includes('/status/')) {
+ return null;
+ }
+ // Keep everything else, with the Authorization header masked
+ return {
+ ...event,
+ headers: event.headers ? redactAuthorization(event.headers) : event.headers,
+ };
+});
+```
+
+The filter applies to every network event the native SDK records: the automatically captured traffic and the events you add with `addNetworkEvent`.
+
+Install the filter **before** `Bugsee.launch`, at the top of your startup code, so the first requests are filtered too. A network filter set before `launch` stays in effect after it, on both platforms. Traffic recorded before the filter is installed is not filtered.
+
+There is one filter at a time. A later call replaces it, and `setNetworkFilter()` or `setNetworkFilter(null)` removes it, so events are recorded without one. A value that is not a function, `null` or `undefined` throws `TypeError` and leaves the previous filter in place. The callback is chosen when an event arrives, so replacing it while an event is being filtered changes the next event, not that one.
+
+:::tip
+Start from a spread of the event you received (`{ ...event, url: ... }`), as in the example. A result that leaves out a field you were sent drops the event; see [What a filter returns](#what-a-filter-returns).
+:::
+
+### The event the filter receives
+
+The callback gets a `NetworkFilterEvent`, a snapshot of the native event:
+
+| Field | Type | Writable | Notes |
+| --- | --- | --- | --- |
+| `id` | `string \| null` | No | The request's id. The events of one request share it. |
+| `url` | `string \| null` | Yes | |
+| `method` | `string \| null` | No | |
+| `headers` | `Record \| null` | Yes | |
+| `body` | `string \| null` | Yes | The body as text. On iOS, a non-empty body that is not valid UTF-8 is left out of the snapshot (the key is missing). |
+| `mechanism` | `string \| null` | No | What recorded the event. Events from `addNetworkEvent` say `react-native`. |
+| `type` | `string \| null` | No | The stage, as the native SDK names it. Android: `before`, `complete`, `redirect`, `error`, `abort`, `timing` or `websocket`. iOS: `websocket`, `udpsocket`, or the HTTP event type (`before`, `complete`, `cancel`, `error`). |
+| `websocketEvent` | `string \| null` | No | The WebSocket event kind, for a WebSocket event; otherwise `null`. |
+| `responseCode` | `number` | No | |
+| `errorDescription` | `string \| null` | Yes | Android only. |
+| `errorShortMessage` | `string \| null` | Yes | Android only. |
+| `statusText` | `string \| null` | Yes | Android only. |
+| `override` | `boolean` | No | Android only; see below. |
+| `redirectedFromURL` | `string \| null` | Yes | iOS only. |
+| `error` | `object \| null` | Yes | iOS only. |
+
+Changes to a field marked "No" are ignored: the native SDK writes back only the writable fields. The rest of the event, including its timestamp and stage, stays as it was.
+
+On Android, one request can reach the filter as more than one event with the same `id` and `type`: a later event that adds a part known only afterward, typically the request body, has `override: true`. Filter it like any other event.
+
+### What a filter returns
+
+| Result | Effect |
+| --- | --- |
+| The event object (changed or not) | Kept, with the writable fields set to what you returned. |
+| `null` or `undefined` | Dropped. |
+| A `Promise` | Waited on; its value is treated the same way. |
+| A string, an array, a function, or any other non-object | Dropped. |
+| An object that leaves out a writable field the snapshot had | Dropped. |
+| A writable field with the wrong type (a `url` or `body` that is not a string or `null`, a header value that is not a string, an iOS `error` that is not an object or `null`) | Dropped. |
+| The callback throws, or the promise rejects | Dropped. |
+
+A kept result must carry `url`, and every other writable field that was present in the snapshot, **including fields whose value was `null`**. Leaving one out, or setting it to `undefined`, drops the event rather than keeping it with that field unredacted. To clear a field, set it to `null`.
+
+A field the snapshot did not have stays absent. Setting it to `null` does not clear anything: `{ ...event, body: event.body ?? null }` leaves an event whose snapshot had no body unchanged.
+
+### Async filters and deadlines
+
+Your callback runs asynchronously, and it may return a promise, for example to read a setting first. Capture does not wait for the answer:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// Your own lookup, for example from storage
+async function blockedHosts(): Promise {
+ return ['tracker.example.com'];
+}
+
+Bugsee.setNetworkFilter(async (event) => {
+ const hosts = await blockedHosts();
+ return hosts.some((host) => event.url?.includes(host)) ? null : event;
+});
+```
+
+The SDK never records the original event in place of an answer. When a filter is slow or never answers:
+
+- **Android**: an event the filter has not answered within about **10 seconds** is dropped. A later answer has no effect.
+- **iOS**: there is no deadline. An answer that arrives late is still applied, and the event is recorded then.
+
+An event that has no URL is dropped before your filter sees it on Android, and reaches your filter with `url: null` on iOS. On both platforms, every event is dropped while no JavaScript runtime is there to answer the filter.
+
+Keep the filter fast: on Android, every event that takes longer than the deadline is lost from the report. On iOS there is no deadline: a slow filter delays the event, and an event the filter never answers is never recorded.
+
+### Reloads
+
+A filter is a function in the JavaScript runtime. When the runtime reloads (a development reload, for example), events still waiting for an answer are dropped.
+
+After the reload, **the filter stays on, but nothing in the new runtime answers it.** Until your code calls `setNetworkFilter` again, every network event is lost: Android drops it after the deadline, and iOS never records it. Call `setNetworkFilter` early in your startup code, or `setNetworkFilter(null)` if the new bundle has no filter.
+
+### Filters and the built-in redaction
+
+With `com.bugsee.option.capture.network.default-sanitizer` on (the default), the native SDKs redact known sensitive values, such as credentials in headers, URL parameters and JSON bodies. Installing a filter changes that differently on each platform:
+
+| Platform | With a filter installed |
+| --- | --- |
+| Android | The built-in redaction runs **before** your filter, so the event you receive is already redacted. Turn the option off to receive the raw event. |
+| iOS | Your filter **replaces** the built-in redaction. The event you receive is not redacted, and your filter must remove what you do not want sent. |
+
+See [Privacy: Network](/sdk/react_native/privacy/network) for redaction guidance.
+
+## Recording custom network events
+
+`Bugsee.addNetworkEvent(event)` records a network exchange the SDK could not see, such as traffic from a native library with its own HTTP stack. The event appears in the report next to the captured traffic.
+
+A request usually produces two events with the same `id`: one when it starts and one when it completes.
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const id = `orders-${Date.now()}`;
+
+Bugsee.addNetworkEvent({
+ id,
+ stage: 'started',
+ url: 'https://api.example.com/orders',
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: '{"sku":"A-100"}',
+});
+
+// ... later, when the response arrives
+Bugsee.addNetworkEvent({
+ id,
+ stage: 'completed',
+ url: 'https://api.example.com/orders',
+ method: 'POST',
+ responseCode: 201,
+ body: '{"order":"1042"}',
+});
+```
+
+The event is timestamped when you call `addNetworkEvent`, so call it when the stage actually happens. There is no timestamp field.
+
+Every added event goes through your [network filter](#filtering-network-events), so an installed filter redacts it the same way as captured traffic. `addNetworkEvent` itself does not call the filter.
+
+### Event fields
+
+| Field | Type | Required | Notes |
+| --- | --- | --- | --- |
+| `url` | `string` | Yes | |
+| `method` | `string` | Yes | The HTTP method, such as `GET`. |
+| `stage` | `string` | No | See [Stages](#stages). Defaults to `completed`. |
+| `id` | `string` | No | Ties the events of one request together. On iOS, an empty or missing id gets a generated one. |
+| `headers` | `Record \| null` | No | Every value must be a string. |
+| `body` | `string \| null` | No | |
+| `responseCode` | `number` | No | A finite number; pass an integer. It is stored as an integer, dropping any fraction. |
+| `statusText` | `string \| null` | No | Stored on Android. iOS ignores it. |
+| `errorDescription` | `string \| null` | No | Stored on Android. iOS ignores it. |
+| `errorShortMessage` | `string \| null` | No | Stored on Android. iOS ignores it. |
+| `redirectedFromURL` | `string \| null` | No | Stored on iOS. Android ignores it. |
+| `error` | `object \| null` | No | Stored on iOS. Android ignores it. |
+
+A field the platform ignores does not stop the event from being recorded.
+
+### Stages
+
+| `stage` | Native stage | Also accepted |
+| --- | --- | --- |
+| `started` | Request started | `before` |
+| `completed` | Request completed (the default) | `complete` |
+| `redirect` | Redirect | |
+| `error` | Request failed | |
+| `aborted` | Request aborted | `abort`, `cancel` |
+| `timings` | Timings received | `timing` |
+| `websocket` | WebSocket | |
+
+On iOS, a `redirect` or `timings` event is recorded as a completed request, and a `websocket` event as a WebSocket message.
+
+### Invalid input
+
+`addNetworkEvent` checks its argument before anything is recorded, and throws `TypeError` (recording nothing) for:
+
+- an argument that is not a plain object (including `null` and arrays),
+- a `url` or `method` that is not a string,
+- a `stage` that is not one of the names above,
+- an `id`, `body`, `statusText`, `errorDescription`, `errorShortMessage` or `redirectedFromURL` that is not a string or `null`,
+- a `responseCode` that is not a finite number,
+- `headers` that is not an object or `null`, or a header value that is not a string,
+- an `error` that is not an object or `null`.
+
+### When nothing is recorded
+
+`addNetworkEvent` returns nothing and does not report whether the event was recorded. When no event can be made from your input, it is dropped and `addNetworkEvent dropped: the SDK made no event` is logged: to logcat on Android, to the device log on iOS. An event added before `launch` is ignored on both platforms. On iOS, so is one added while the status is still `Launching`, right after `launch` resolves; see [A resolved launch is not live capture](/sdk/react_native/lifecycle#a-resolved-launch-is-not-live-capture).
+
+Record custom events after `launch`, and on iOS once the status is `Launched`.
+
+## Related pages
+
+- [Privacy: Network](/sdk/react_native/privacy/network): redacting headers, URLs and bodies.
+- [Configuration](/sdk/react_native/configuration): every launch option.
+- [Console logs](/sdk/react_native/logs): the matching log filter.
+- [Installation: Android](/sdk/react_native/installation#android): the Bugsee Gradle plugin.
diff --git a/docs/sdk/react_native/notification-relay.md b/docs/sdk/react_native/notification-relay.md
new file mode 100644
index 0000000..fcc2302
--- /dev/null
+++ b/docs/sdk/react_native/notification-relay.md
@@ -0,0 +1,131 @@
+---
+title: "Notification relay"
+description: "Bugsee.notify in React Native SDK 7.x: sending a title, body, severity and fields straight to your messaging integrations and webhooks, without creating a bug report."
+sidebar_position: 19
+slug: "/sdk/react_native/notification-relay"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+`Bugsee.notify(...)` sends a title, an optional body, an optional severity and optional string fields to the messaging integrations and webhooks you have set up for the app, **without** creating a bug report. Notification relay has no equivalent in 6.x.
+
+## When to use it
+
+A bug report (video, logs, network traffic, an issue in the dashboard) is a lot to pay for when all you need is to tell a person what happened: "the payment webhook returned 500 for order 42". If your code already knows that, `notify` is the direct path: one call, a few strings, delivered to the destinations your team already has.
+
+It is not a replacement for bug reports. It records no video, logs or network traffic, and creates no Bugsee issue, so there is nothing to open and investigate afterward. When you need a session someone can replay, use [bug reporting](/sdk/react_native/manual/bug-reporting) or [crash & error reporting](/sdk/react_native/manual/crash-error-reporting).
+
+## API
+
+```text
+Bugsee.notify(
+ title: string,
+ body?: string | null,
+ severity?: IssueSeverity,
+ fields?: Readonly> | null,
+ urgent?: boolean,
+): void
+```
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+// Title only
+Bugsee.notify('Payment webhook failed');
+
+// With a body and a severity
+Bugsee.notify('Payment webhook failed', 'Stripe returned a 500 for order 42', IssueSeverity.High);
+
+// With fields
+Bugsee.notify('Payment webhook failed', 'Stripe returned a 500 for order 42', IssueSeverity.High, {
+ order_id: '42',
+ provider: 'stripe',
+ status_code: '500',
+});
+```
+
+| Argument | Rules |
+| --- | --- |
+| `title` | Required. A string that is not empty or only whitespace. |
+| `body` | A string. Omitted or `null`, the notification has no body. |
+| `severity` | An `IssueSeverity` value, an integer from 1 to 5: `VeryLow`, `Medium`, `High`, `Critical`, `Blocker`. Omitted, it is sent as `0`, which both SDKs treat as unset. |
+| `fields` | An object whose values are all strings. Omitted or `null`, the notification has no fields. The object is copied when you call `notify`. |
+| `urgent` | A boolean. Omitted, the call is not urgent; see [Urgent notifications](#urgent-notifications). |
+
+To pass `fields` or `urgent` without a severity, pass `undefined` for the arguments you skip: `null` is not accepted for `severity`.
+
+`notify` checks its arguments before anything is queued, and throws (sending nothing) for:
+
+| Input | Thrown |
+| --- | --- |
+| More than five arguments | `TypeError` |
+| A `title` that is not a string, or is empty or only whitespace | `TypeError` |
+| A `body` that is not a string or `null` | `TypeError` |
+| A `severity` that is not a number | `TypeError` |
+| A `severity` that is not an integer from 1 to 5 | `RangeError` |
+| `fields` that is not an object or `null` (an array, for example), or a field value that is not a string | `TypeError` |
+| An `urgent` that is not a boolean | `TypeError` |
+
+Field order: on Android, the fields keep the order of `Object.keys` (the order you wrote them in, except that integer-like keys such as `'1'` and `'42'` come first); on iOS, the order is not specified.
+
+### Before launch
+
+A call made before `Bugsee.launch` is ignored: it is not queued, and nothing is sent. On iOS, a call made while the SDK is still launching may be dropped. Call `notify` after `launch` has resolved.
+
+`notify` returns nothing and takes no callback, so you cannot tell from the app whether a notification reached the server.
+
+## Offline behavior and batching
+
+Each notification is stored on the device before anything is sent, so it normally survives the app being killed, and it waits while the device is offline. The queue is bounded on both platforms: at most 500 notifications or 1 MB, the oldest evicted first, and notifications older than 72 hours are discarded. If writing a notification to disk fails, it is kept in memory only and lost if the app is killed before it is sent. The native SDKs upload queued notifications in batches, not one request per call, and honor the `wifiOnlyUpload` option.
+
+The `com.bugsee.option.config.notify-flush-delay` option (milliseconds, default `0`) sets how long the SDK waits before it sends what is queued. With `0` it starts as soon as a notification is stored; a positive value lets calls made in quick succession share one batch. It has no effect on an urgent notification's immediate attempt; an urgent notification that cannot go out at once waits with the queue, delay included.
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.setCustomOption('com.bugsee.option.config.notify-flush-delay', 2000);
+
+Bugsee.launch('', options);
+```
+
+There is no option to turn notification relay on or off in the SDK: it is available whenever the SDK is launched.
+
+The queue is bounded differently per platform. Android: a notification larger than 256 KiB once serialized (the title, body, severity and fields, together with the user, environment and attribute data the SDK adds) is dropped rather than queued, silently unless the SDK's internal logging is on. iOS: there is no limit per notification, but the queue holds at most 500 notifications and 1 MB, and the oldest are dropped, silently, when it is over either.
+
+### Urgent notifications
+
+With `urgent` set to `true`, the SDK tries to send that one notification at once, ahead of the queue, when the network is available (and allowed by `wifiOnlyUpload`). Otherwise the notification is queued like any other and sent with the next batch. An urgent call never sends the older queued notifications; it only decides whether this one skips ahead. It also needs an active session; on Android, the call must also be made in the app's main process (an iOS app has only one).
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+Bugsee.notify(
+ 'Checkout is failing',
+ 'Five payment errors in the last minute',
+ IssueSeverity.Critical,
+ { region: 'eu-west' },
+ true,
+);
+```
+
+## Delivery
+
+Calling `notify` delivers nothing on its own. Notification relay has to be turned on for the app in Bugsee, and its destinations chosen; until then the call succeeds on the device and nothing arrives.
+
+- **Integrations**: each application mapping of an integration has a _Relay_ option, off by default, that forwards relayed notifications to it; see [Configuring integrations](/integrations/configuration#mapping-applications). A recipe receives a relayed notification in the shape of an issue; see [Event-based recipes](/integrations/recipes/recipes_notifications).
+- **Webhooks**: a subscribed webhook receives the [`notification.relayed`](/webhooks/events#notificationrelayed) event, which documents the payload.
+
+## Privacy
+
+A relayed notification carries the title, body, severity and fields you pass, plus the current [user identifier](/sdk/react_native/user-session-data#user-identity), the [attributes](/sdk/react_native/user-session-data#attributes) you set, and an environment snapshot (app, platform and hardware details). It carries no video, logs, network traffic or view hierarchy.
+
+Nothing scrubs the title, body or fields before they are sent: the log, network and breadcrumb filters do not apply to them. Do not put anything in them that must not leave the device.
+
+## Related pages
+
+- [Bug reporting](/sdk/react_native/manual/bug-reporting): when you need a full report.
+- [User & session data](/sdk/react_native/user-session-data): the identifier and attributes a notification carries.
+- [Configuration](/sdk/react_native/configuration): every launch option.
diff --git a/docs/sdk/react_native/overview.mdx b/docs/sdk/react_native/overview.mdx
new file mode 100644
index 0000000..3f25c7a
--- /dev/null
+++ b/docs/sdk/react_native/overview.mdx
@@ -0,0 +1,80 @@
+---
+title: "Overview"
+description: "What the Bugsee React Native SDK 7.x records and detects, how it wraps the native iOS and Android SDKs, and what your app needs to run it."
+sidebar_position: 0
+slug: "/sdk/react_native/overview"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+The Bugsee React Native SDK (`@bugsee/react-native`) captures what happened before a bug: a video of the screen, network traffic, console logs and the steps that led to it. It attaches that timeline to crash, error and bug reports you can replay in the Bugsee dashboard.
+
+The package is built on the native Bugsee SDKs for Android and iOS, and gives both platforms one JavaScript API: a report from a React Native app is the same report a native app produces, with the JavaScript layer added.
+
+## What Bugsee records
+
+Every report carries a synchronized timeline of the session that led up to it:
+
+- **Video**: a rolling recording of the screen. Wrap anything that must never be recorded in ``; see [Privacy: Video](/sdk/react_native/privacy/video).
+- **Network**: requests your app makes through `fetch` and `XMLHttpRequest` travel through the platform's networking stack, where the SDK records them (on Android, only with the Bugsee Gradle plugin applied; see [Installation](/sdk/react_native/installation#android)). You can add events from other stacks yourself and filter what is recorded; see [Network events](/sdk/react_native/network).
+- **Console logs**: `console.error`, `warn`, `log`, `info` and `debug` are forwarded to Bugsee and still print as before; see [Console logs](/sdk/react_native/logs).
+- **Breadcrumbs**: system events recorded automatically (such as app lifecycle changes), plus breadcrumbs you add. The package records no automatic touch or navigation breadcrumbs for React components. Off until you turn them on; see [Breadcrumbs](/sdk/react_native/breadcrumbs).
+- **Custom events, traces and attributes**: see [Custom events & traces](/sdk/react_native/events-and-traces) and [User & session data](/sdk/react_native/user-session-data).
+- **Performance (APM)**: [transactions and spans](/sdk/react_native/performance) you start from JavaScript.
+
+## What Bugsee detects
+
+The SDK turns problems into reports automatically:
+
+- **JavaScript exceptions**: `Bugsee.launch()` installs global handlers for uncaught errors and unhandled promise rejections. An [error boundary](/sdk/react_native/error-boundary) reports render errors.
+- **Native crashes**: on Android, uncaught Java and Kotlin exceptions and native (NDK) crashes; on iOS, uncaught Objective-C exceptions and fatal signals, including Swift runtime traps. See [Native crashes](/sdk/react_native/manual/crash-error-reporting#native-crashes).
+- **Handled errors** you report yourself; see [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting).
+- **Manual reports**: let users shake the device to report, or open the report dialog or upload a report from code; see [Bug reporting](/sdk/react_native/manual/bug-reporting).
+
+## How it works
+
+- **One package.** `@bugsee/react-native` brings the native SDKs with it: autolinking adds the Android module, and the iOS SDK comes through the package's `Package.swift` when your app uses React Native's Swift Package Manager integration (0.87 and later), or through the package's podspec with CocoaPods. You don't add the native SDKs yourself: no Podfile pod, no Maven dependency.
+- **Launch from JavaScript.** One call, `Bugsee.launch(token, options)`, starts the SDK; see [Installation](/sdk/react_native/installation) and [Lifecycle & status](/sdk/react_native/lifecycle).
+- **One option namespace.** The same `com.bugsee.option.*` keys work on both platforms, so one options object configures both; see [Configuration](/sdk/react_native/configuration).
+- **Privacy on the device.** Mask views with ``, and filter or drop network, log and breadcrumb data before it is recorded; see [Privacy](/sdk/react_native/privacy/overview).
+- **Readable release reports.** Release builds can upload JavaScript source maps, Android mapping and native symbols, and iOS dSYMs, so crash frames resolve to your source. An Expo app gets this from the [config plugin](/sdk/react_native/expo); a bare app adds a few build steps; see [Symbolication](/sdk/react_native/symbolication/overview).
+- **Automatic upload.** Reports upload to the dashboard in the background.
+
+The in-app feedback chat ships separately, as `@bugsee/react-native-feedback`, so apps that never show it do not depend on it; see [Feedback](/sdk/react_native/feedback).
+
+## Requirements
+
+| | |
+| --- | --- |
+| React Native | 0.81 or later, with the New Architecture enabled |
+| JavaScript engine | Hermes (React Native's default) |
+| iOS | 15.0 or later |
+| Android | API 21 or later |
+
+The New Architecture is the default from React Native 0.76. On 0.81 it can still be turned off; this package requires it on.
+
+Hermes is required. JavaScriptCore (Hermes off) is not supported: React Native removed JSC from core in 0.81, and the community package that replaces it, `@react-native-community/javascriptcore`, does not work with current React Native.
+
+## Versions
+
+This beta, `7.0.0-beta3`, is built on these native SDKs:
+
+| Platform | Native SDK | Notes |
+| --- | --- | --- |
+| Android | `com.bugsee:bugsee-android` 7.4.2 | Bugsee Gradle plugin 4.0.8 for release uploads and Android network capture |
+| iOS | Bugsee iOS SDK 7.0.0-beta7 | The iOS SDK is itself a beta |
+
+`@bugsee/react-native` 7.x replaces `react-native-bugsee` 6.x. They are different packages with different APIs, not an upgrade in place: remove the old package and follow [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+
+## Get started
+
+Head to [Installation](/sdk/react_native/installation) for a React Native CLI app, or [Expo](/sdk/react_native/expo) if you use Expo prebuild. From there, [Configuration](/sdk/react_native/configuration) covers the launch options, and [Privacy](/sdk/react_native/privacy/overview) covers redaction.
+
+## Related pages
+
+- [Installation](/sdk/react_native/installation): add the package and launch the SDK.
+- [Expo](/sdk/react_native/expo): the config plugin for Expo prebuild.
+- [Configuration](/sdk/react_native/configuration): launch options for both platforms.
+- [Lifecycle & status](/sdk/react_native/lifecycle): launch, stop, relaunch and querying status.
diff --git a/docs/sdk/react_native/performance.mdx b/docs/sdk/react_native/performance.mdx
new file mode 100644
index 0000000..156b565
--- /dev/null
+++ b/docs/sdk/react_native/performance.mdx
@@ -0,0 +1,223 @@
+---
+title: "Performance monitoring"
+description: "Measure flows in your React Native app with Bugsee React Native SDK 7.x transactions and spans: startTransaction, startSpan, getActiveSpan, the span object, statuses, sampling, and what the native SDKs capture on their own."
+sidebar_position: 21
+slug: "/sdk/react_native/performance"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Performance monitoring (APM) measures how long the flows in your app take, such as a checkout or a screen load, and attaches those measurements to Bugsee reports.
+
+## Concept
+
+APM is built around two primitives, **transactions** and **spans**:
+
+- A **transaction** is the root of a performance trace. It has a name (`Checkout`), an operation type (`ui.checkout`), optional attributes, and a status.
+- A **span** is a unit of work inside a transaction. Spans form a tree: a span can have child spans for finer steps. Each span has its own operation, description, attributes and status.
+
+When you start a span while another span is active, the new span becomes a child of the active one, so you get the hierarchy without passing parent objects around.
+
+Transactions and spans you start from JavaScript are the same transactions and spans the SDK records natively: each JavaScript object stands for one of them, and every call on it applies to it.
+
+## What is captured automatically
+
+The React Native package records no spans from JavaScript on its own: there are no automatic spans for React renders, navigation, or `fetch` calls made in JavaScript. Add them with the API below.
+
+While performance monitoring is on, the SDK also measures native components, not React screens, on its own:
+
+- **Android**: the providers listed in the native SDK reference, [Android built-in providers](/sdk/android/performance#built-in-providers). Some of them, such as database and file I/O spans, depend on the Bugsee Gradle plugin.
+- **iOS**: an `http.client` transaction for each HTTP request (only while network capture is on), `file.*` child spans for file operations made inside an active transaction, a `ui.load` transaction for each native screen (view controller) that appears, and one `app.start.cold` or `app.start.warm` transaction for app startup. The iOS documentation has no performance page for 7.x yet; the option keys are in the [iOS 7.x migration guide](/sdk/ios/v7/migration#25-performance).
+
+## Transactions and spans
+
+```ts
+import Bugsee, { SpanStatus } from '@bugsee/react-native';
+
+async function checkout(items: number, pay: () => Promise): Promise {
+ const tx = Bugsee.startTransaction('Checkout', 'ui.checkout', { 'cart.items': items });
+ try {
+ const validate = Bugsee.startSpan('validate', 'Validate cart');
+ validate.finish(SpanStatus.OK);
+
+ const charge = tx.startChildSpan('http.client', 'POST /charge');
+ try {
+ await pay();
+ charge.finish(SpanStatus.OK);
+ } catch (error) {
+ charge.finish(SpanStatus.Error);
+ throw error;
+ }
+
+ tx.finish(SpanStatus.OK);
+ } catch (error) {
+ tx.finish(SpanStatus.Error);
+ throw error;
+ }
+}
+```
+
+### `startTransaction`
+
+`Bugsee.startTransaction(name, operation, attributes?)` starts a transaction and returns it as a `BugseeTransaction`. The transaction becomes the active span, so a later `startSpan` is its child.
+
+| Argument | Type | Description |
+| --- | --- | --- |
+| `name` | `string` | The transaction name. Must not be empty or only whitespace. |
+| `operation` | `string` | The operation type, such as `ui.load`. Must not be empty or only whitespace. |
+| `attributes` | object | Optional initial attributes. Each value is a string, a finite number or a boolean. |
+
+### `startSpan`
+
+`Bugsee.startSpan(operation, description?)` starts a span as a child of the active span. `description` is a string, `null` or left out.
+
+### `startChildSpan`
+
+`span.startChildSpan(operation, description?)` starts a span under that specific span, whatever is active. Use it when the parent matters, such as a transaction whose steps run in parallel promises or across `await`s where another transaction may have started in between.
+
+### `getActiveSpan`
+
+`Bugsee.getActiveSpan()` returns the active span, or `null` when there is none. Use it to add an attribute from code that does not have the span:
+
+```ts
+Bugsee.getActiveSpan()?.setAttribute('retry.count', 2);
+```
+
+If JavaScript already holds an object for that span, you get the same object back.
+
+### Which span is active
+
+All your JavaScript calls see the same active span:
+
+| Platform | Thread the span calls run on |
+| --- | --- |
+| Android | The thread the JavaScript calls arrive on. |
+| iOS | The main thread: each call runs there synchronously. |
+
+## Performance monitoring off
+
+With `com.bugsee.option.performance.enabled` set to `false`, the SDK returns no-op spans, on both platforms: `startTransaction` and `startSpan` still return objects, and calls on them do nothing. `startSpan` with no active transaction also returns a no-op span. You do not need to check for `null`.
+
+Call `finish` on these objects too: it releases the resources they hold.
+
+## The span object
+
+`BugseeSpan` and `BugseeTransaction` have these properties:
+
+| Property | Type | Description |
+| --- | --- | --- |
+| `spanId` | `string` | The span's id. |
+| `traceId` | `string` | The id of the trace the span belongs to. |
+| `operation` | `string` | The operation. |
+| `description` | `string \| null` | The description. |
+| `status` | `SpanStatus` | The status. |
+| `finished` | `boolean` | Whether the span has finished. |
+| `attributes` | object | The attributes. |
+| `name` | `string` | Transaction only: the transaction name. |
+| `sampled` | `boolean` | Transaction only: whether the transaction won the sample-rate draw when it started (see [Sampling](#sampling)). In this beta the value has no effect, because the standalone upload is not active. It is read once at start and never updated: a transaction that adaptive sampling promotes when it finishes still reads `false`. |
+
+The properties are read when the object is created and then follow the changes you make through it. They are not read again.
+
+The setters return the span, so calls can be chained:
+
+| Method | Description |
+| --- | --- |
+| `setName(name)` | Sets the span's **operation** on both SDKs. On a transaction, `name` is not changed. |
+| `setDescription(description)` | Sets the description, or clears it with `null`. |
+| `setAttribute(key, value)` | Adds or replaces an attribute. `value` is a string, a finite number or a boolean. |
+| `setStatus(status)` | Sets the status. |
+| `startChildSpan(operation, description?)` | Starts a child span of this span. |
+| `finish(status?)` | Finishes the span and releases it. |
+
+```ts
+const span = Bugsee.startSpan('db.query', 'load cart')
+ .setAttribute('cache', false)
+ .setDescription('load cart from storage');
+span.finish();
+```
+
+### Finishing
+
+Call `finish` exactly once on every span and transaction you start. The span stays open until then.
+
+`finish()` with no argument is the SDK's own no-argument finish, which ends the span as `OK` on both platforms, **even after `setStatus`**: it overwrites a status you set earlier. To end with another status, pass it to `finish` (for example `finish(SpanStatus.Error)`). The object's `status` property is not updated by `finish`, so after `setStatus(SpanStatus.Error)` and a bare `finish()` it still reads `Error` while the recorded span is `OK`.
+
+Finishing a span also ends its child spans that are still open, with the status `Cancelled`, on both platforms. The package releases those children too, and their objects behave as finished.
+
+After a span is finished, every method on its object throws `BugseeSpanError` with the code `SpanErrorCode.HandleDead` (`E_SPAN_HANDLE_DEAD`), including a second `finish`. Properties can still be read.
+
+```ts
+import { BugseeSpanError, SpanErrorCode, type BugseeSpan } from '@bugsee/react-native';
+
+function markLate(span: BugseeSpan): void {
+ try {
+ span.setAttribute('late', true);
+ } catch (error) {
+ if (error instanceof BugseeSpanError && error.code === SpanErrorCode.HandleDead) {
+ return; // the span was already finished
+ }
+ throw error;
+ }
+}
+```
+
+### Development reloads
+
+When the JavaScript runtime reloads, the spans of the old runtime are released **without being finished**, so a transaction still open stays open. The objects from the old runtime are gone. In the new runtime, `getActiveSpan` can return a span that is still active.
+
+## `SpanStatus`
+
+| Constant | Value |
+| --- | --- |
+| `SpanStatus.OK` | `0` |
+| `SpanStatus.Error` | `1` |
+| `SpanStatus.Timeout` | `2` |
+| `SpanStatus.Cancelled` | `3` |
+| `SpanStatus.DeadlineExceeded` | `4` |
+| `SpanStatus.Unknown` | `5` |
+
+## Errors
+
+The calls check their input before doing anything:
+
+| Input | Thrown |
+| --- | --- |
+| `name`, `operation`, a `setName` value or a `setAttribute` key that is not a string, or is empty or only whitespace | `TypeError` |
+| `attributes` that is not an object (including `null` and arrays) | `TypeError` |
+| An attribute value that is not a string, a finite number or a boolean | `TypeError` |
+| A `description` that is not a string or `null` | `TypeError` |
+| A status that is not a number | `TypeError` |
+| A status that is not a whole number from `0` to `5` | `RangeError` |
+| Any method on a finished span | `BugseeSpanError` (`E_SPAN_HANDLE_DEAD`) |
+
+If no span can be started at all, `startTransaction` and `startSpan` throw an ordinary `Error`, and `startChildSpan` throws `BugseeSpanError` (`E_SPAN_HANDLE_DEAD`).
+
+## Sampling
+
+These launch options control APM. They have no accessor; set them with `setCustomOption` or in a plain map.
+
+| Key | Default | Description |
+| --- | --- | --- |
+| `com.bugsee.option.performance.enabled` | `true` | Master switch. `false` makes every span a no-op and stops the native providers. |
+| `com.bugsee.option.performance.sample-rate` | `0.01` | Probability (`0` to `1`) that a transaction is sampled for a standalone APM upload. Accepted, but that upload is not active in this beta. |
+| `com.bugsee.option.performance.adaptive-sampling` | `true` | Promote transactions that lost the random draw into the standalone upload. Accepted, but that upload is not active in this beta. |
+| `com.bugsee.option.performance.upload-mode` | `"batched"` | Android only. How a standalone upload would send sampled transactions. Accepted, but that upload is not active in this beta. |
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.setCustomOption('com.bugsee.option.performance.sample-rate', 0.1);
+
+Bugsee.launch('', options);
+```
+
+Performance data reaches Bugsee **with reports**: the captured transactions are written into every report. In this beta, transactions are not sent on their own, on either platform: the standalone APM upload that the sampling options are meant for is not active. The sample rate therefore changes nothing that is sent today; only `com.bugsee.option.performance.enabled` does.
+
+## Related pages
+
+- [Configuration](/sdk/react_native/configuration): every launch option.
+- [Network events](/sdk/react_native/network): network capture on each platform.
+- Native SDK reference: [Android performance monitoring](/sdk/android/performance) and, for iOS, the performance keys in the [iOS 7.x migration guide](/sdk/ios/v7/migration#25-performance).
diff --git a/docs/sdk/react_native/privacy/breadcrumbs.md b/docs/sdk/react_native/privacy/breadcrumbs.md
new file mode 100644
index 0000000..0ffd276
--- /dev/null
+++ b/docs/sdk/react_native/privacy/breadcrumbs.md
@@ -0,0 +1,118 @@
+---
+title: "Privacy: Breadcrumbs"
+description: "How to keep sensitive data out of the breadcrumbs Bugsee React Native SDK 7.x records: the breadcrumb options, and redacting or dropping breadcrumbs with setBreadcrumbFilter."
+sidebar_position: 5
+slug: "/sdk/react_native/privacy/breadcrumbs"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Breadcrumbs record the steps leading up to an issue: the ones you add with `Bugsee.addBreadcrumb`, and the ones the native SDKs record themselves, such as app lifecycle changes, system events and HTTP requests. Their messages and data can carry a URL with a token in it, an identifier, or a value from your own code. See [Breadcrumbs](/sdk/react_native/breadcrumbs) for how they are recorded; this page covers how to keep sensitive data out of them.
+
+## Breadcrumb options
+
+Breadcrumb capture is **off by default**, on both platforms. Leaving it off is the simplest control: no breadcrumb is recorded, yours or the native SDK's.
+
+| Option | Key | Default | Description |
+| --- | --- | --- | --- |
+| `captureBreadcrumbs` | `com.bugsee.option.capture.breadcrumbs` | `false` | Record breadcrumbs. |
+| (no accessor) | `com.bugsee.option.capture.breadcrumbs.extras` | `false` | Attach raw system data to the breadcrumbs the native SDK records for system events: the `Intent` extras of system broadcasts on Android, the notification `userInfo` of device events on iOS. That data is not yours to vet, so leave it off unless you need it. |
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.captureBreadcrumbs = true;
+// Leave com.bugsee.option.capture.breadcrumbs.extras at its default, false
+
+Bugsee.launch('', options);
+```
+
+On iOS, the keyboard and focus breadcrumbs are not recorded during a [blackout](/sdk/react_native/privacy/video#blackout).
+
+## Network URLs in breadcrumbs
+
+The breadcrumb the native SDK records for an HTTP request can carry the request's URL. Your [network filter](/sdk/react_native/privacy/network) does **not** reach breadcrumbs: a request it drops or rewrites can still appear, with its URL, in the breadcrumb trail.
+
+- **iOS**: the built-in query-parameter redaction (`com.bugsee.option.capture.network.default-sanitizer`) is applied to breadcrumb URLs, but a network filter is not.
+- **Android**: the URL is recorded as it is.
+
+Repeat your URL rules in the breadcrumb filter, as in the example below.
+
+## Redacting with a breadcrumb filter
+
+`Bugsee.setBreadcrumbFilter(callback)` sees every breadcrumb before it is recorded, yours and the native SDK's. Return the breadcrumb with its fields redacted to keep it, or `null` to drop it.
+
+The example below does not depend on how the native SDKs name their categories: it scrubs every string in the message and the data.
+
+```ts
+import Bugsee, { type BreadcrumbSnapshot } from '@bugsee/react-native';
+
+const SECRET_PARAMS = /([?&](?:token|access_token|code|session)=)[^\s]*/gi;
+const EMAIL = /[\w.%+-]+@[\w-]+(?:\.[\w-]+)+/g;
+
+function scrub(text: string): string {
+ return text.replace(SECRET_PARAMS, '$1').replace(EMAIL, '');
+}
+
+// Scrubs every string in a breadcrumb's data, at any depth
+function scrubValue(value: unknown): unknown {
+ if (typeof value === 'string') {
+ return scrub(value);
+ }
+ if (Array.isArray(value)) {
+ return value.map(scrubValue);
+ }
+ if (value !== null && typeof value === 'object') {
+ const out: Record = {};
+ for (const [key, item] of Object.entries(value)) {
+ out[key] = scrubValue(item);
+ }
+ return out;
+ }
+ return value;
+}
+
+Bugsee.setBreadcrumbFilter((crumb: BreadcrumbSnapshot) => {
+ // Drop a whole category of your own breadcrumbs
+ if (crumb.category === 'auth') {
+ return null;
+ }
+
+ // Start from a spread, so every field you were sent is still there
+ const redacted: BreadcrumbSnapshot = { ...crumb };
+ if (crumb.message !== undefined) {
+ redacted.message = scrub(crumb.message);
+ }
+ if (crumb.data !== undefined && crumb.data !== null) {
+ redacted.data = scrubValue(crumb.data);
+ }
+ return redacted;
+});
+
+// Install filters first, then launch.
+// Bugsee.launch('', options);
+```
+
+What makes it a safe boundary:
+
+- **It fails closed.** The breadcrumb is dropped, not recorded unredacted, when the callback throws, its promise rejects, it returns something that is not an object, it leaves out a writable field the breadcrumb had, or a value is invalid. Set `data` to `null` to clear it; leaving it out drops the whole breadcrumb.
+- **No late recording of the original.** Neither platform sets a deadline for the breadcrumb filter, and the original is never recorded in place of an answer. A callback that never settles means the breadcrumb is never recorded, so make sure yours always settles.
+- **Your own breadcrumbs keep their filter.** A breadcrumb you pass to `addBreadcrumb` is answered by the filter that was installed at that moment, even if you clear or replace it on the same turn.
+
+What it does not cover:
+
+- **Breadcrumbs recorded before the filter is installed.** Call `setBreadcrumbFilter` before `Bugsee.launch`, at the top of your startup code.
+- **Android auto-launch.** With `autoLaunch`, the SDK records from process start on Android, before any JavaScript runs, and breadcrumbs recorded before your code calls `setBreadcrumbFilter` are not filtered. Do not use auto-launch if that window must be filtered.
+- **A cleared filter.** `setBreadcrumbFilter(null)` removes the filter, and breadcrumbs are then recorded unfiltered.
+- **Development reloads.** After a JavaScript reload the filter stays on, but nothing in the new runtime answers it, so no breadcrumb is recorded until your code calls `setBreadcrumbFilter` again. Nothing is recorded unfiltered.
+
+For your own breadcrumbs, the simplest redaction is not to put the value in at all: build the `message` and `data` you pass to `addBreadcrumb` from what you are willing to send. See [Filtering breadcrumbs](/sdk/react_native/breadcrumbs#filtering-breadcrumbs) for the full contract: the fields of the breadcrumb, what each return value does, and which values `data` accepts.
+
+## Related pages
+
+- [Breadcrumbs](/sdk/react_native/breadcrumbs): turning them on, `addBreadcrumb`, and the filter contract.
+- [Privacy: Network](/sdk/react_native/privacy/network): the network filter, which does not reach breadcrumbs.
+- [Privacy overview](/sdk/react_native/privacy/overview): every privacy control.
diff --git a/docs/sdk/react_native/privacy/cleanup.md b/docs/sdk/react_native/privacy/cleanup.md
new file mode 100644
index 0000000..5a30e37
--- /dev/null
+++ b/docs/sdk/react_native/privacy/cleanup.md
@@ -0,0 +1,94 @@
+---
+title: "Privacy: Cleanup"
+description: "How to delete the data Bugsee React Native SDK 7.x has collected on the device with deleteCollectedDataOnDevice, what it keeps, and how to clear attributes and the user identifier at sign-out or when consent is withdrawn."
+sidebar_position: 7
+slug: "/sdk/react_native/privacy/cleanup"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+The native SDKs keep the rolling capture (video, logs, network events and the rest of the timeline), data set aside for reports, and reports waiting to be uploaded on the device. `Bugsee.deleteCollectedDataOnDevice` deletes the captured data, for example when a user signs out, deletes their account, or withdraws consent.
+
+## Deleting collected data
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function deleteBugseeData(): Promise {
+ // While the SDK runs, the deletion is refused
+ await Bugsee.stop();
+ return Bugsee.deleteCollectedDataOnDevice(true);
+}
+```
+
+`deleteCollectedDataOnDevice(includingIntermediate)` resolves to whether the data was deleted.
+
+| `includingIntermediate` | Deletes | Keeps |
+| --- | --- | --- |
+| `false` | The rolling capture data. | Intermediate data, and finished reports waiting to be uploaded. |
+| `true` | The rolling capture data, and the intermediate data: the snapshots set aside for reports that are not assembled yet, and exported reports (documented for Android; not specified for iOS in this beta). | Finished reports waiting to be uploaded. |
+
+- **The SDK must be stopped.** While it is launched, both platforms refuse the deletion, delete nothing, and the promise resolves `false`. Await `Bugsee.stop()` first; it resolves once the SDK has stopped.
+- **The result can be late or early.** Android: the promise resolves when the deletion has finished. iOS: the promise resolves `false` if the deletion has not finished within 1.5 seconds, even though it may still complete afterward.
+- **Finished reports are kept, and uploaded later.** Neither value deletes a report that has already been assembled and is waiting for upload: it is uploaded once the SDK runs again. This beta has no call that deletes those too.
+
+## Clearing attributes and the user identifier
+
+`deleteCollectedDataOnDevice` deletes captured data. It does not clear the [user identifier or attributes](/sdk/react_native/user-session-data), which persist across launches and are sent with every report. Clear them yourself, while the SDK is still running:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function forgetUser(): Promise {
+ // 1. Clear what identifies the user, while the SDK runs
+ Bugsee.clearUserIdentifier();
+ await Bugsee.clearAllAttributes();
+
+ // 2. Stop, then delete what was captured
+ await Bugsee.stop();
+ const deleted = await Bugsee.deleteCollectedDataOnDevice(true);
+
+ // 3. Relaunch later, once you may record again
+ return deleted;
+}
+```
+
+To remove a single attribute, use `Bugsee.clearAttribute(name)`.
+
+## When to call it
+
+| Event | What to do |
+| --- | --- |
+| The user signs out | Clear the user identifier and the attributes that describe them. Delete collected data too if the next user of the device must not appear in reports with the previous one's session. |
+| The user withdraws consent | Clear the identifier and attributes, stop the SDK, delete collected data, and do not launch again until consent is given. |
+| The user deletes their account | As for withdrawn consent. Reports already uploaded live on the Bugsee server, not on the device; this API does not reach them. |
+
+After `stop`, nothing more is recorded until you call `Bugsee.launch` again; see [Lifecycle & status](/sdk/react_native/lifecycle).
+
+## Pausing capture without deleting
+
+To keep a sensitive flow out of the video without stopping the SDK, use a [blackout](/sdk/react_native/privacy/video#blackout): logs and network events keep recording, and nothing is deleted. To stop all capture, call `Bugsee.stop()`, and `Bugsee.launch` again later.
+
+## Automatic retention
+
+The rolling capture keeps only the last `duration` seconds, on both platforms. How much space reports waiting to be uploaded may take differs per platform:
+
+| Option | Key | Android | iOS |
+| --- | --- | --- | --- |
+| `maxDataSize` | `com.bugsee.option.config.max-data-size` | `150` MB by default. Past any of these limits, whole reports are removed: errors first, then bug reports, then crashes, oldest first. | `50` by default, but **not enforced** in this beta: the key is accepted and has no effect. |
+| `maxPendingReports` (Android) | `com.bugsee.option.config.max-pending-reports` | `30` by default: the most reports kept waiting to be sent. | No equivalent. |
+| `maxPendingReportAge` (Android) | `com.bugsee.option.config.max-pending-report-age` | `30` days by default: the oldest a report waiting to be sent may get. | No equivalent. |
+
+:::caution[iOS: no cap on pending reports in this beta]
+On iOS, nothing in this beta limits the reports waiting to be uploaded. On a device that stays offline, or keeps failing to upload, they accumulate until they are sent, and `deleteCollectedDataOnDevice` does not remove them.
+:::
+
+See [Configuration](/sdk/react_native/configuration) for every option.
+
+## Related pages
+
+- [Privacy: Report](/sdk/react_native/privacy/report): what a report sends.
+- [User & session data](/sdk/react_native/user-session-data): the attribute API.
+- [Lifecycle & status](/sdk/react_native/lifecycle): stop and launch.
diff --git a/docs/sdk/react_native/privacy/logs.md b/docs/sdk/react_native/privacy/logs.md
index b04cfdc..008cfcc 100644
--- a/docs/sdk/react_native/privacy/logs.md
+++ b/docs/sdk/react_native/privacy/logs.md
@@ -1,43 +1,109 @@
---
-title: "Privacy and console logs"
-description: "Disable or sanitize console log collection in React Native to prevent personally identifiable data from being included in Bugsee reports."
+title: "Privacy: Console logs"
+description: "How to keep sensitive data out of the logs Bugsee React Native SDK 7.x records: turning capture off, level thresholds per platform, and redacting or dropping lines with setLogFilter."
sidebar_position: 3
slug: "/sdk/react_native/privacy/logs"
---
-## Disabling log collection
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
-Console log collection can be disabled completely by providing corresponding launch flags. Refer to [configuration](/sdk/react_native/configuration/) and look for **captureLogs** launch option for more info.
+Log lines often carry more than you meant to share: an access token in a URL, an e-mail address in a debug message, a payload dumped while a feature was being built. Bugsee records your JavaScript `console.*` output, the native logs of the app, and the lines you send with `Bugsee.log`; see [Console logs](/sdk/react_native/logs) for where each comes from. This page covers how to keep sensitive data out of them.
-## Sanitizing console logs
+## Disabling log capture
-Bugsee automatically captures all standard application console logs, but they can be protected as well.
+Set `captureLogs` to `false` to stop capturing logs automatically: the package no longer forwards `console.*` output, and the native SDKs no longer capture the native logs.
-For every event to be recorded, Bugsee will call your method and provide you with an object with captured data. It is your
-method's responsibility to clean up all user identifiable data from that structure and return it back to Bugsee.
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
-### Providing handler
+const options = createDefaultLaunchOptions();
+options.captureLogs = false;
-You should pass a callback to Bugsee.setLogFilter().
+Bugsee.launch('', options);
+```
+
+Lines you send with `Bugsee.log` are still recorded with `captureLogs` off: the option turns off only what is captured automatically.
+
+## What a console line contains
+
+The package converts each argument of a `console.*` call with `String()` and joins them with a space. Objects are **not** serialized: `console.log('session', session)` is recorded as `session [object Object]`, so the fields of an object you log, a token among them, do not reach the report. A value you turn into text yourself, with `JSON.stringify` or a template string, is recorded in full.
+
+## Level thresholds
+
+`captureLogsLevel` drops lines less severe than the level you set. It is a way to keep chatty debug output out of reports, but it applies to different lines on each platform:
+
+```ts
+import Bugsee, { LogLevel, createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+options.captureLogsLevel = LogLevel.Warning; // keep Error and Warning
+
+Bugsee.launch('', options);
+```
-```javascript
-Bugsee.setLogFilter(function (logEvent) {
- // Filter log event here or return
- // null to prevent it from being
- // recorded at all
- return logEvent;
+| Platform | `captureLogsLevel` applies to |
+| --- | --- |
+| Android | Only the lines the SDK reads from logcat (React Native itself and native modules). `console.*` lines and `Bugsee.log` lines are recorded whatever their level. |
+| iOS | Every line the SDK records, `console.*` and `Bugsee.log` lines included. |
+
+On Android, the level therefore does not keep a `console.debug` line out of a report. Use a [log filter](#redacting-with-a-log-filter) for that. See [Which lines the level applies to](/sdk/react_native/logs#which-lines-the-level-applies-to) for details.
+
+## Redacting with a log filter
+
+`Bugsee.setLogFilter(callback)` is the redaction boundary for logs: it sees each line before it is recorded, and what it returns is what the report gets. Return a changed string to redact the line, or `null` to drop it.
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const REDACTION_RULES: ReadonlyArray<[RegExp, string]> = [
+ // Bearer tokens and token-like query parameters
+ [/(bearer\s+)[\w.~+/-]+=*/gi, '$1'],
+ [/([?&](?:token|access_token|api_key|session)=)[^&\s]+/gi, '$1'],
+ // E-mail addresses
+ [/[\w.%+-]+@[\w-]+(?:\.[\w-]+)+/g, ''],
+ // Card-like digit runs
+ [/\b\d(?:[ -]?\d){12,18}\b/g, ''],
+];
+
+Bugsee.setLogFilter((line) => {
+ // Drop whole categories of lines
+ if (line.startsWith('[payments]')) {
+ return null;
+ }
+ return REDACTION_RULES.reduce(
+ (text, [pattern, replacement]) => text.replace(pattern, replacement),
+ line,
+ );
});
-// To stop using provided filter callback, just pass null
-Bugsee.setLogFilter(null);
+// Install filters first, then launch.
+// Bugsee.launch('', options);
```
-### Logging Events
+What makes it a safe boundary:
+
+- **It fails closed.** A line is dropped, not recorded unfiltered, when the callback throws, its promise rejects, or it returns something that is not a string. A line the filter does not answer is not recorded either: on Android it is dropped after about 10 seconds; on iOS a line whose filter never answers is never recorded.
+- **It changes only the text.** The level and timestamp of the line stay as they were.
+- **It sees the captured lines**: `console.*` output and the native log lines, on both platforms.
+
+What it does not cover:
+
+- **`Bugsee.log` lines skip it by default.** As in the native SDKs, a line you send with `Bugsee.log` is recorded without going through the filter. Pass `true` as the third argument for a line that may carry user data: `Bugsee.log(message, LogLevel.Info, true)`. See [`requiresFiltering`](/sdk/react_native/logs#requiresfiltering).
+- **Lines recorded before the filter is installed.** Call `setLogFilter` before `Bugsee.launch`, at the top of your startup code. A filter set before `launch` stays in effect after it.
+- **Android auto-launch.** With `autoLaunch`, the SDK records from process start on Android, before any JavaScript runs, and lines captured before your code calls `setLogFilter` are recorded unfiltered. Do not use auto-launch if that window must be filtered.
+- **A cleared filter.** `setLogFilter(null)` removes the filter, and lines are then recorded unfiltered.
+- **Development reloads.** On Android, after a JavaScript reload, lines are recorded **unfiltered** until the new runtime calls `setLogFilter` again. On iOS they are dropped until then. Install the filter first thing in your startup code, before anything logs. See [Reloads](/sdk/react_native/logs#reloads).
+
+Keep the filter fast and synchronous where you can: every captured line in the session goes through it, and on Android a line the filter has not answered within about 10 seconds is dropped. On iOS there is no deadline, so a slow filter delays lines rather than losing them. See [Filtering log lines](/sdk/react_native/logs#filtering-log-lines) for the full contract, including what each return value does.
-The handler is going to be called one time for each logged message.
+:::note
+The SDK sets a log filter of its own on the native side, on both platforms, to drop duplicate copies of console lines. A log filter you set from native code with `setLogEventFilter` is replaced by it, so redact logs with `Bugsee.setLogFilter`.
+:::
+## Related pages
-|Property|Description|Type|Read only|Notes
-|---|---|---|---|---|
-|text|Text being logged|String|NO||
-|level|Logging level|Number|NO|1 - error, 2 - warning, 3 - info, 4 - debug, 5 - verbose|
\ No newline at end of file
+- [Console logs](/sdk/react_native/logs): where lines come from, `Bugsee.log`, and the filter contract.
+- [Privacy: Network](/sdk/react_native/privacy/network): the matching network filter.
+- [Privacy overview](/sdk/react_native/privacy/overview): every privacy control.
diff --git a/docs/sdk/react_native/privacy/network.md b/docs/sdk/react_native/privacy/network.md
index f26fa43..bae79c1 100644
--- a/docs/sdk/react_native/privacy/network.md
+++ b/docs/sdk/react_native/privacy/network.md
@@ -1,44 +1,168 @@
---
-title: "Privacy and Network traffic"
-description: "Disable or filter captured network requests and responses in React Native to strip sensitive data before it is recorded by Bugsee."
-sidebar_position: 2
+title: "Privacy: Network"
+description: "How to keep credentials and personal data out of the network traffic Bugsee React Native SDK 7.x records: turning capture off, body options, the built-in redaction on each platform, and redacting events with setNetworkFilter."
+sidebar_position: 4
slug: "/sdk/react_native/privacy/network"
---
-## Disabling network traffic collection
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
-Network traffic collection can be disabled completely by providing corresponding launch flags. Refer to [configuration](/sdk/react_native/configuration/) and look for **monitorNetwork** launch option for more info.
+Recorded network traffic is one of the most useful parts of a report, and one of the most sensitive: request headers carry credentials, URLs carry tokens, and bodies carry whatever the user typed. The native SDKs record the traffic (see [Network events](/sdk/react_native/network)); this page covers how to keep sensitive values out of it.
+## Disabling network capture
-## Sanitizing data
+Set `captureNetwork` to `false` to record no network traffic at all:
-Bugsee captures network activity from the application and stores headers and in some cases body of the request and response.
-In order to allow you to hide user identifiable and other sensitive data from these network logs, we let you hook into network capturing by installing network filter handler that will be called for every event about to be recorded.
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
-For every event to be recorded, Bugsee will call your method and provide you with an object containing captured data. It is your method's responsibility to clean up all user identifiable data from that structure and return it back to Bugsee.
+const options = createDefaultLaunchOptions();
+options.captureNetwork = false;
-```javascript
-Bugsee.setNetworkFilter(function (netEvent) {
- // Filter event here as required, or return null to ignore it
- return netEvent;
+Bugsee.launch('', options);
+```
+
+## Body options
+
+These options limit which bodies are kept. They have no accessor; set them with `setCustomOption`:
+
+| Key | Default | Description |
+| --- | --- | --- |
+| `com.bugsee.option.capture.network.body-size-limit` | `20480` | Largest request or response body captured, in bytes. |
+| `com.bugsee.option.capture.network.body-without-type` | `false` | Also keep bodies that declare no content type. Leave it off unless you need them. |
+
+A body over the limit is dropped, not cut. On iOS both options apply after your network filter, so the filter still sees an oversized body or one without a content type; on Android they apply before it.
+
+Neither option removes headers or URL parameters. Use the built-in redaction and a [network filter](#redacting-with-a-network-filter) for those.
+
+## The built-in redaction
+
+With `com.bugsee.option.capture.network.default-sanitizer` on (the default), known sensitive values are replaced with ``. Key matching is case-insensitive.
+
+| | Android | iOS |
+| --- | --- | --- |
+| Headers | `Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`, `X-Auth-Token`, `X-CSRF-Token`, `X-Forwarded-For`, `X-Real-IP`, and any header whose name contains `password`, `secret`, `token`, `session` or `apikey`, among others | The same nine names, matched exactly. |
+| URL parameters and bodies | Known sensitive keys, and any key whose name contains `password`, `secret`, `token`, `session` or `apikey`, among others, in query parameters and in JSON, form-encoded and `key: value` bodies. Also removes `user:password@` credentials from URLs, and redacts the error texts (`errorDescription`, `errorShortMessage`). | A fixed list of key names, matched exactly (`password`, `secret`, `token`, `access_token`, `refresh_token`, `api_key`, `authorization`, card numbers, `cvv`, `ssn`, `pin`, `private_key` and a few variants), in query parameters, in the redirect URL and in JSON bodies. Bodies that are not JSON are left unchanged. |
+
+Native SDK reference: [Android network privacy](/sdk/android/privacy/network#a-filter-replaces-the-built-in-redaction) (the full Android list) and [iOS network privacy](/sdk/ios/privacy/network#automatic-sanitization).
+
+The built-in redaction knows nothing about your own API. On iOS, a header such as `X-Session-Id` is recorded as it is; Android redacts it because its name contains `session`. A JSON field such as `otp`, or a value in a plain-text body, is recorded as it is on both platforms unless your filter removes it.
+
+### With a network filter installed
+
+Installing a filter changes the built-in redaction differently on each platform:
+
+| Platform | With a filter installed |
+| --- | --- |
+| Android | The built-in redaction runs **before** your filter, so the event you receive is already redacted, and your filter adds to it. Turn the option off to receive the raw event. |
+| iOS | Your filter **replaces** the built-in redaction. The event you receive is not redacted, and your filter must remove everything you do not want sent, including the headers in the table above. |
+
+Write one filter that redacts everything you need on both platforms, as in the example below, rather than relying on the built-in redaction.
+
+## Redacting with a network filter
+
+`Bugsee.setNetworkFilter(callback)` sees each network event before it is recorded, the captured traffic and the events you add with `addNetworkEvent`. Return the event with its fields redacted to keep it, or `null` to drop it.
+
+The example below is a starting point, not an exhaustive policy: review it against your data. Its lists repeat the iOS built-in header names and keys, because on iOS the filter replaces the built-in redaction, and add a few names for your own API. All names are matched case-insensitively.
+
+```ts
+import Bugsee, { type NetworkFilterEvent } from '@bugsee/react-native';
+
+// Header names (lowercase). The first nine are the iOS built-in list.
+const SECRET_HEADERS = new Set([
+ 'authorization', 'proxy-authorization', 'cookie', 'set-cookie', 'x-api-key',
+ 'x-auth-token', 'x-csrf-token', 'x-forwarded-for', 'x-real-ip',
+ 'x-session-id', // your own API
+]);
+
+// URL query parameter and JSON key names (lowercase). All but the last line are the iOS built-in list.
+const SECRET_KEYS = new Set([
+ 'password', 'passwd', 'pass', 'secret', 'client_secret',
+ 'token', 'access_token', 'refresh_token', 'id_token', 'auth_token',
+ 'api_key', 'apikey', 'authorization',
+ 'credit_card', 'creditcard', 'card_number', 'cardnumber', 'cvv', 'cvc', 'cvv2',
+ 'ssn', 'social_security', 'pin', 'private_key', 'privatekey',
+ 'otp', 'code', 'session', // your own API
+]);
+
+function redactUrl(url: string | null): string | null {
+ if (url === null) {
+ return null;
+ }
+ return url.replace(/([?&])([^=]+)=[^]*/g, (match: string, sep: string, name: string) =>
+ SECRET_KEYS.has(name.toLowerCase()) ? `${sep}${name}=` : match,
+ );
+}
+
+function redactHeaders(headers: Record): Record {
+ const out: Record = {};
+ for (const [name, value] of Object.entries(headers)) {
+ out[name] = SECRET_HEADERS.has(name.toLowerCase()) ? '' : value;
+ }
+ return out;
+}
+
+function redactBody(body: string): string | null {
+ try {
+ const parsed: unknown = JSON.parse(body);
+ return JSON.stringify(parsed, (key, value: unknown) =>
+ SECRET_KEYS.has(key.toLowerCase()) ? '' : value,
+ );
+ } catch {
+ return null; // not JSON: drop the body rather than guess
+ }
+}
+
+Bugsee.setNetworkFilter((event: NetworkFilterEvent) => {
+ // Drop requests to an endpoint whose traffic must never be recorded
+ if (event.url?.includes('/v1/identity/')) {
+ return null;
+ }
+
+ // Start from a spread, so every field you were sent is still there
+ const redacted: NetworkFilterEvent = { ...event, url: redactUrl(event.url) };
+ if (event.headers) {
+ redacted.headers = redactHeaders(event.headers);
+ }
+ if (typeof event.body === 'string') {
+ redacted.body = redactBody(event.body);
+ }
+ if (event.redirectedFromURL !== undefined) {
+ redacted.redirectedFromURL = redactUrl(event.redirectedFromURL); // iOS only
+ }
+ return redacted;
});
-// To remove previously set network filter handler, just pass null to setNetworkFilter()
-Bugsee.setNetworkFilter(null);
+// Install filters first, then launch.
+// Bugsee.launch('', options);
```
-### Network Events
+What makes it a safe boundary:
+
+- **It fails closed.** The event is dropped, not recorded unredacted, when the callback throws, its promise rejects, it returns something that is not an event object, or it leaves out a writable field the event had. To clear a field, set it to `null`; leaving it out drops the whole event.
+- **Late answers are not recorded unfiltered.** Android: an event the filter has not answered within about 10 seconds is dropped. iOS: there is no deadline, and an answer that arrives late is still applied then.
+- **It writes back only the writable fields**: `url`, `headers` and `body` on both platforms, `errorDescription`, `errorShortMessage` and `statusText` on Android, and `redirectedFromURL` and `error` on iOS. The error texts can quote a URL, so redact them too if your URLs carry secrets.
+
+What it does not cover:
+
+- **Traffic recorded before the filter is installed.** Call `setNetworkFilter` before `Bugsee.launch`, at the top of your startup code.
+- **Android auto-launch.** With `autoLaunch`, the SDK records from process start on Android, before any JavaScript runs, and network events captured before your code calls `setNetworkFilter` are not filtered by it. Do not use auto-launch if that window must be filtered.
+- **A cleared filter.** `setNetworkFilter(null)` removes the filter, and events are then recorded without it.
+- **Development reloads.** After a JavaScript reload the filter stays on, but nothing in the new runtime answers it, so every network event is lost until your code calls `setNetworkFilter` again. Nothing is recorded unfiltered.
+- **Breadcrumbs.** The network filter does not reach breadcrumbs. If you turn breadcrumbs on, an HTTP request breadcrumb can carry the request's URL: on iOS with the built-in query-parameter redaction applied, on Android as it is. Repeat your URL rules in a [breadcrumb filter](/sdk/react_native/privacy/breadcrumbs).
+- **Performance transactions.** With performance monitoring on (the default), each HTTP request also becomes a performance transaction that carries its URL, and it is included in reports. Your network filter does not reach it. On Android the built-in redaction is applied to that URL. On iOS it is not: see the warning below.
+- **HTTP error reports.** With `com.bugsee.option.detect.http-errors` on, the request's URL, normalized, goes into the report's `http_url` attribute on iOS. Remove it in a [report handler](/sdk/react_native/privacy/report) if needed.
+
+:::warning[iOS: performance transactions record full URLs]
+On iOS, the performance transaction of each HTTP request records the request's full URL, query string included, as it is: neither the built-in redaction nor your network filter applies to it. If your URLs carry tokens or personal data, turn performance monitoring off with `com.bugsee.option.performance.enabled: false`, or keep secrets out of URLs. See [Performance monitoring](/sdk/react_native/performance).
+:::
-The handler is going to be called several times for each network request, depending on its life-cycle. Usually for
-successful requests it's going to be called twice, once with the request event (request headers and body) and once after
-completion and will contain headers and body of the response.
+See [Filtering network events](/sdk/react_native/network#filtering-network-events) for the full contract: the fields of the event, what each return value does, and the deadlines.
+## Related pages
-|Property|Description|Type|Read only|Notes
-|---|---|---|---|---|
-|type|Type of network event|String|YES| 'begin', 'complete', 'cancel' or 'error'|
-|method|HTTP Request Method|String|YES|'GET', 'POST', etc...
-|url|Network event URL|String|NO|
-|redirected_from|URL of Network event that we were redirected from|String|NO|
-|body|Body|String|NO|Raw body of the request or response where available.
-|headers|HTTP Headers|Object|NO|Key-value map of HTTP headers associated with the event.|
\ No newline at end of file
+- [Network events](/sdk/react_native/network): what is recorded, `addNetworkEvent`, and the filter contract.
+- [Privacy: Breadcrumbs](/sdk/react_native/privacy/breadcrumbs): redacting breadcrumbs.
+- [Privacy overview](/sdk/react_native/privacy/overview): every privacy control.
diff --git a/docs/sdk/react_native/privacy/overview.md b/docs/sdk/react_native/privacy/overview.md
index 9163397..064918d 100644
--- a/docs/sdk/react_native/privacy/overview.md
+++ b/docs/sdk/react_native/privacy/overview.md
@@ -1,28 +1,41 @@
---
title: "Privacy overview"
-description: "Overview of privacy considerations for Bugsee in React Native and the tools available to prevent or sanitize PII in reports."
-sidebar_position: 0
+description: "The privacy controls of Bugsee React Native SDK 7.x: what a report can contain, and where to mask, filter, redact or delete it before it leaves the device."
+sidebar_position: 1
slug: "/sdk/react_native/privacy/overview"
---
-Bugsee SDK does not continuously stream any personal data. The reports are stored locally on the phone in a cyclical buffer. Reports are being sent only when triggered by a crash, through a bug reporting UI or from an application's code.
-Data sent along with the reports may include video recording of screen, network and console logs. These may potentially contain PII (Personally Identifiable Information).
-
-It is the sole responsibility of the application developers to remove any such data from the reports before it leaves the users’ device.
-
-Bugsee provides the tools and means to either prevent some data from being collected or clean the data during the collection process:
-
-* [Video and Touch](/sdk/react_native/privacy/video/)
-* [Network](/sdk/react_native/privacy/network/)
-* [Console logs](/sdk/react_native/privacy/logs/)
-
-
-
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+Bugsee does not stream data continuously. The SDK keeps what it captures in a rolling buffer on the device, as long as the `duration` launch option, and send it only when a report is created: by a crash or an error, from the report dialog, or from your code. The data in a report (screen video, touches, console and native logs, network traffic, breadcrumbs, attributes and the text the user typed) can contain personal data, so the SDK gives you a control at each point where that data is recorded.
+The controls work in four places:
+- **On screen.** `` masks a component in the video and the report screenshot, and drops the touches on it. `Bugsee.setSecureRectangles` masks regions you measure yourself. `Bugsee.startBlackout()` blanks the whole screen for a sensitive flow. The native SDKs also mask password fields on their own.
+- **At record time.** A log, network or breadcrumb filter sees each event before it is recorded, and can rewrite or drop it. The filters fail closed: a filter that throws, rejects, or returns something it should not drops the event rather than recording it unfiltered.
+- **Before upload.** A report handler can change the summary, description, severity, labels and attributes of a report before it is sent.
+- **On the device.** Launch options turn whole streams off, and `Bugsee.deleteCollectedDataOnDevice` deletes the captured data while the SDK is stopped.
+| Page | Covers |
+| --- | --- |
+| [Video](/sdk/react_native/privacy/video) | ``, `setSecureRectangles`, `startBlackout` / `endBlackout`, password fields, the view hierarchy, and the video and screenshot options. |
+| [Console logs](/sdk/react_native/privacy/logs) | Turning log capture off, `captureLogsLevel`, and redacting lines with `setLogFilter`. |
+| [Network](/sdk/react_native/privacy/network) | Turning network capture off, body options, the built-in redaction, and redacting events with `setNetworkFilter`. |
+| [Breadcrumbs](/sdk/react_native/privacy/breadcrumbs) | Breadcrumb options and redacting breadcrumbs with `setBreadcrumbFilter`. |
+| [Report](/sdk/react_native/privacy/report) | What a report carries, what a report handler can change, attributes and the user identifier. |
+| [Cleanup](/sdk/react_native/privacy/cleanup) | `deleteCollectedDataOnDevice`, and clearing attributes and the user identifier. |
+## Things to know
+- **Install filters before `Bugsee.launch`.** A filter applies to what is recorded after it is installed, so set the log, network and breadcrumb filters, and the report handler, at the top of your startup code.
+- **Android auto-launch.** With `autoLaunch` (see [Expo](/sdk/react_native/expo#auto-launch-on-android)), the SDK records from process start on Android, before any JavaScript runs. Logs, network events and breadcrumbs captured before your code calls the filter setters are recorded unfiltered, and the regions you mark with `` or `setSecureRectangles` are not masked until they mount or are set. Automatic masking of password fields and `FLAG_SECURE` windows does not depend on them; see [Privacy: Video](/sdk/react_native/privacy/video#password-fields). Do not use auto-launch if that window must be filtered.
+- **Filters and development reloads.** A filter is a function in the JavaScript runtime. After a JavaScript reload the filters stay on while nothing in the new runtime answers them, so network events and breadcrumbs are lost until your code installs the filter again. On Android the log filter is turned off on reload, so log lines are recorded **unfiltered** until `setLogFilter` runs again. Install the filters first thing in your startup code.
+- **Performance spans.** With performance monitoring on (the default), the SDK records a performance transaction for each HTTP request, carrying its URL, and on iOS spans for file operations, carrying file paths. They are included in every report. Your network filter does not reach them. Span URLs get the built-in network redaction on Android, and are recorded in full, query string included, on iOS; see [Privacy: Network](/sdk/react_native/privacy/network). `com.bugsee.option.performance.enabled` set to `false` turns them off. See [Performance monitoring](/sdk/react_native/performance).
+- **The platforms differ.** On Android the built-in network redaction runs before your network filter; on iOS your filter replaces it. See [Privacy: Network](/sdk/react_native/privacy/network).
+- **The report handler is not a redaction boundary for every report.** It does not run for every crash (an Android native crash never reaches it), and it cannot remove the video, the screenshot, the logs or the network traffic from a report. Data that must never leave the device has to be kept out where it is recorded: masked on screen, or dropped by a filter.
+Bugsee also sends data outside reports: [`Bugsee.notify`](/sdk/react_native/notification-relay) notifications, and the messages of the [feedback chat](/sdk/react_native/feedback). Neither carries video or logs.
+It remains the responsibility of the application developer to keep sensitive data out of reports before they leave the device.
diff --git a/docs/sdk/react_native/privacy/report.md b/docs/sdk/react_native/privacy/report.md
new file mode 100644
index 0000000..fd579ac
--- /dev/null
+++ b/docs/sdk/react_native/privacy/report.md
@@ -0,0 +1,105 @@
+---
+title: "Privacy: Report"
+description: "What a Bugsee React Native SDK 7.x report carries, what a report handler can and cannot change before upload, and how to keep attributes and the user identifier free of sensitive data."
+sidebar_position: 6
+slug: "/sdk/react_native/privacy/report"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+A report bundles what the SDK captured with what the user, or your code, put into it. The capture streams have their own controls, covered on the other privacy pages. This page covers the rest: the report's own fields, attributes and the user identifier, and what a [report handler](/sdk/react_native/report-handler) can do about them before the report is sent.
+
+## What a report carries
+
+| Part | Where it comes from | Control |
+| --- | --- | --- |
+| Video, screenshot, touches, view hierarchy | Screen capture | [Privacy: Video](/sdk/react_native/privacy/video) |
+| Console and native logs | Log capture and `Bugsee.log` | [Privacy: Console logs](/sdk/react_native/privacy/logs) |
+| Network traffic | Network capture and `Bugsee.addNetworkEvent` | [Privacy: Network](/sdk/react_native/privacy/network) |
+| Breadcrumbs | `Bugsee.addBreadcrumb` and the native SDKs | [Privacy: Breadcrumbs](/sdk/react_native/privacy/breadcrumbs) |
+| Custom events and traces | `Bugsee.event`, `Bugsee.trace` | What you pass in. See [Custom events & traces](/sdk/react_native/events-and-traces). |
+| Summary, description, labels, severity | The report dialog, `upload`, `createReport`, or the error that raised the report | A report handler |
+| E-mail address | The report dialog's e-mail field | The report handler cannot read or change it in this beta. |
+| Attributes and the user identifier | `Bugsee.setAttribute`, `Bugsee.setUserIdentifier` | [Attributes and the user identifier](#attributes-and-the-user-identifier); per report, a report handler |
+| Attachments | Your report handler or created report | You add them; see below. |
+
+## What a report handler can change
+
+A report handler runs before a report is sent and can rewrite its text fields. Use it to remove what a user typed into the dialog, or what an error message quoted:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const CARD_NUMBER = /\b\d(?:[ -]?\d){12,18}\b/g;
+const EMAIL = /[\w.%+-]+@[\w-]+(?:\.[\w-]+)+/g;
+
+function scrub(text: string | undefined): string | null {
+ return text === undefined ? null : text.replace(CARD_NUMBER, '[CARD]').replace(EMAIL, '[EMAIL]');
+}
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ const { summary, description } = await report.read();
+ await report.update({
+ summary: scrub(summary),
+ description: scrub(description),
+ // Keep this attribute off reports, but not off the device
+ attributes: { accountEmail: null },
+ });
+ },
+});
+```
+
+Run the redaction in `onAfterReportCreated`: for the report dialog, `onBeforeReportCreated` runs before the dialog opens, so it does not see what the user types. `onAfterReportCreated` can run more than once for the same report, which is harmless for a redaction like this one. Install the handler before `Bugsee.launch`.
+
+| You can | With |
+| --- | --- |
+| Rewrite or clear the summary and the description | `setSummary`, `setDescription`, or `update`; `null` clears |
+| Replace the labels | `setLabels` (replaces the whole list) |
+| Change the severity | `setSeverity` |
+| Remove one attribute, or all of them, from this report | `setAttribute(name, null)`, `clearAttributes()`, or `update` |
+| Add attachments | `addFileAttachment`, `addDataAttachment` |
+
+A change made in the report handler applies to that report only. It does not touch the attributes stored on the device.
+
+### What it cannot do
+
+- **It cannot drop a report.** To keep data out of one, redact it.
+- **It cannot remove the video, the screenshot, the logs or the network traffic.** Neither SDK can leave the video out of a single report. Keep sensitive content out of the capture itself.
+- **It cannot remove an attachment** once added.
+- **It does not see every report.** An Android native (NDK) crash, Android's early recovery at startup, and reports recovered before JavaScript runs under Android auto-launch never reach it. On iOS, a report recovered at launch gets only a short, best-effort window. See [Async callbacks and deadlines](/sdk/react_native/report-handler#async-callbacks-and-deadlines).
+
+So a report handler is the place to scrub user-entered text and adjust what your own code put in, not a guarantee for data that must never leave the device. A callback that throws does not stop the report: the changes made before the throw are kept, and the report is sent.
+
+## Attributes and the user identifier
+
+The user identifier and every attribute are sent with every report, and with every [`Bugsee.notify`](/sdk/react_native/notification-relay) notification. Attributes **persist across launches** until you clear them.
+
+- Do not put passwords, tokens or other secrets in them.
+- Keep personal data to what you need to find a user's reports. An internal user ID is usually enough; you rarely need an e-mail address or a name.
+- Clear them when the user signs out, and when they withdraw consent:
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function onSignOut(): Promise {
+ Bugsee.clearUserIdentifier();
+ await Bugsee.clearAllAttributes();
+}
+```
+
+The [feedback chat](/sdk/react_native/feedback) uses the user identifier too: on both platforms, an identifier that contains an `@` is taken as the user's e-mail address, and on iOS the chat's messages carry the identifier when the user gave no e-mail address.
+
+See [User & session data](/sdk/react_native/user-session-data) for the attribute API.
+
+## Reports you build yourself
+
+A report from `createReport` carries the fields you set on it, and the report handler still runs on it. See [Bug reporting](/sdk/react_native/manual/bug-reporting#build-a-report-yourself).
+
+## Related pages
+
+- [Report handler](/sdk/react_native/report-handler): the full contract, deadlines and errors.
+- [Privacy: Cleanup](/sdk/react_native/privacy/cleanup): deleting collected data on the device.
+- [Privacy overview](/sdk/react_native/privacy/overview): every privacy control.
diff --git a/docs/sdk/react_native/privacy/video.md b/docs/sdk/react_native/privacy/video.md
index 43d04a3..4bbebe3 100644
--- a/docs/sdk/react_native/privacy/video.md
+++ b/docs/sdk/react_native/privacy/video.md
@@ -1,68 +1,229 @@
---
-title: "Privacy and video"
-description: "Pause screen recording, mark UI components as protected, and define secure rectangles to hide sensitive content from Bugsee video in React Native."
-sidebar_position: 1
+title: "Privacy: Video"
+description: "How to keep sensitive screens out of Bugsee React Native SDK 7.x recordings with BugseeSecure, setSecureRectangles and blackout, what the view hierarchy contains, and the video options that matter for privacy."
+sidebar_position: 2
slug: "/sdk/react_native/privacy/video"
---
-# Going dark
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
-In some rare cases you might want to conceal the whole screen and stop recording events completely. The following APIs will come in handy, no data is being gathered between the calls to pause and resume.
+Bugsee records the screen so that a report shows what the user saw. Anything on screen ends up in that video and in the report screenshot unless you mask it. The React Native SDK gives you three tools: `` for components, `Bugsee.setSecureRectangles` for regions you measure yourself, and a blackout for a whole flow.
-```javascript
-// To stop video recording use
-Bugsee.pause();
+## Disabling video
-// And to continue
-Bugsee.resume();
-```
+Turn screen recording off entirely with the `captureVideo` launch option. The report screenshot has its own switch, `com.bugsee.option.capture.screenshot`; see [Video and screenshot options](#video-and-screenshot-options).
-### Marking view as protected in code
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
-You can mark any view as protected and in this case it will be covered with a black box automatically. Use `Bugsee.toggleProtected()` method to achieve this. It accepts two parameters: `component` and `state`. First should be a reference to the component you want to hide/show and second is a boolean value of `protected` flag (either `true` or `false`).
+const options = createDefaultLaunchOptions();
+options.captureVideo = false;
+options.setCustomOption('com.bugsee.option.capture.screenshot', false);
-```jsx
- this.setState({text})}
- value={this.state.text} ref={comp => Bugsee.toggleProtected(comp, true)}
-/>
+Bugsee.launch('', options);
```
+## Hiding a component: ``
+
+Wrap anything that must never be recorded in ``:
-### Protecting by coordinates
+```tsx
+import { Text } from 'react-native';
+import { BugseeSecure } from '@bugsee/react-native';
-Bugsee allows hiding screen area by absolute coordinates as well. Notice that iOS and Android approaches to hiding specific area differ a bit.
+function AccountNumber({ value }: { value: string }) {
+ return (
+
+ {value}
+
+ );
+}
+```
-```javascript
-// Values are: X, Y, Width, Height
-Bugsee.addSecureRect(10, 10, 400, 600);
+While it is mounted and enabled, the part of it that is on screen is masked in the video and in the report screenshot, and touches on it are dropped from the report.
+
+| Prop | Type | Default | Description |
+| --- | --- | --- | --- |
+| `enabled` | `boolean` | `true` | While `false`, nothing is masked and nothing is measured. |
+| Other `View` props | | | `` renders a `View`, and passes `style`, `onLayout` and the other `View` props to it, except `ref` (it does not forward a ref) and `collapsable` (always `false`, so the view is never flattened away). Style it as you would the `View` it replaces. |
+
+How the mask follows the component:
+
+- **On screen only.** The mask is cut to every ancestor that clips the component (a `ScrollView`'s viewport, a view with `overflow: 'hidden'`). A component scrolled fully out of sight masks nothing, so it does not mask, or drop the taps on, what is shown in its place.
+- **Movement.** It re-measures itself on every layout and every 100 ms, and every frame while it moves, so it follows scrolling. It also follows react-native-screens push and pop transitions, sliding ``s, and `Animated` transforms driven by the native driver. Where it cannot tell exactly where the component is drawn, it masks more rather than less.
+- **Hidden screens.** A component on an inactive react-native-screens screen (an inactive tab that stays mounted, for example), or hidden with `display: 'none'` or a hidden ``, masks nothing.
+- **Growth at once, removal late.** A larger area is masked at once. What the component stops covering, by shrinking, moving, being hidden or unmounting, stays masked for about half a second (up to about 800 ms around a screen or Modal transition), because the native side may still draw it there. Only `enabled={false}` unmasks at once.
+- **Fails closed.** A measurement that fails leaves the last mask in place.
+
+The view hierarchy marks everything inside `` as secure; see [The view hierarchy](#the-view-hierarchy).
+
+### Known limits
+
+- Content that mounts in a pushed screen or an opening `` after it arrived (behind a spinner, for example), or that is first shown on the screen a pop uncovers, is masked for the rest of the transition. When a screen came or went is known only if a `` saw it; otherwise the first one to look masks as if it happened then: the whole screen, or the Modal's band, for under a second.
+- A value a native event drives (an `Animated.event` in an `Animated` component's `onScroll` or `onGestureEvent`, or `Animated.attachNativeEvent`, which React Native's own `ScrollView` uses for `stickyHeaderIndices`) moves with the scroll or the gesture. What it transforms is masked wherever it can be drawn, for as long as the event is attached, idle or not:
+ - through a clamped interpolation, one whose ends are flat (a swipeable row without overshoot), or a `diffClamp`: over its output range;
+ - on Android, through a `ScrollView`'s `contentOffset`, vertical or horizontal (a collapsing or parallax header): over the offsets the `ScrollView` can reach, plus 64 dp either way for a fling's overrun. A view inside the content of that `ScrollView` (a sticky header, from `stickyHeaderIndices` or a `SectionList`) is masked over the `ScrollView`'s whole viewport;
+ - anything else (a gesture's translation through an interpolation that extends, an iOS `ScrollView`, which bounces and can be scrolled anywhere by `scrollTo`, a `ScrollView` in another React root, or under a scale other than 1): the whole surface around it, cut by the clipping ancestors above it.
+- Native events are followed from when `@bugsee/react-native` is first evaluated: with Metro's `inlineRequires`, its first use. Import it (or call `Bugsee.launch`) at the top of `index.js` to follow them from the start. A value made native before then is masked as if anything could drive it, until JavaScript next animates or sets it. A native event attached without `Animated` (code that calls React Native's native Animated module itself) is not seen at all.
+- A transform animated from JavaScript (`useNativeDriver: false`) is followed every frame while its animation runs. Other styles a JavaScript animation moves (`top`, `left`, `margin`, a size) are followed by the 100 ms re-measure only.
+- Reanimated runs its animations on the UI thread, out of JavaScript's sight. A Reanimated component whose style sets a transform through an animated style, sets a shared value inline, or uses a CSS animation or transition masks the whole surface around it. Other Reanimated motion (an animated style that adds a transform only later, layout animations, `entering` / `exiting`, shared element transitions) is not followed.
+- An interactive back gesture (iOS swipe-back, Android predictive back) moves a mounted screen without anything JavaScript can see.
+- The mask is published in the same JavaScript task that starts a native animation (or sets, resets or offsets an `Animated.Value`), but the two reach native code separately: under heavy load, the animation's first frame could still be drawn before the mask lands.
+- How an ancestor clips is read from its React props. An `overflow` changed natively (through `setNativeProps` or a native-driven style) is not seen.
+
+Where these limits matter, combine `` with a [blackout](#blackout) for the duration of the sensitive flow.
+
+## Password fields
+
+The native SDKs mask password fields on their own, with no Bugsee call:
+
+- **iOS**: a text field or text view whose `secureTextEntry` is on. React Native's `` is one.
+- **Android**: a text field with a password input type, which React Native's `` sets, and, on Android 8.0 and later, a text field whose autofill hint marks it as a password or credit card field. React Native sets that hint from the `autoComplete` prop: `password`, `password-new`, `cc-number`, `cc-csc`, and `cc-exp` with its `-day`, `-month` and `-year` variants.
+
+On iOS the masking lasts while `secureTextEntry` is on: a "show password" toggle that turns it off also lifts it. On Android, a field the SDK has detected as a password or card field stays masked until it leaves the screen. Wrap the field in `` if you need the same behavior on both.
+
+On Android, windows with the system `FLAG_SECURE` flag are also protected, unless you turn off the Android-only option `com.bugsee.option.capture.respect-flag-secure` (default `true`). An activity whose own window has `FLAG_SECURE` is treated as a full blackout while it is shown: black frames, no recorded input, and no view hierarchy.
+
+## Hiding a region: `setSecureRectangles`
+
+`Bugsee.setSecureRectangles(rectangles, display?)` masks regions you measure yourself, for content `` cannot wrap:
+
+```tsx
+import { useEffect, useRef, useState, type ReactNode } from 'react';
+import { View } from 'react-native';
+import Bugsee from '@bugsee/react-native';
+
+type Region = { x: number; y: number; width: number; height: number };
+
+// Every mounted MaskedRegion, so that each call publishes all of them:
+// setSecureRectangles replaces the whole list.
+const regions = new Map();
+const publishAll = () => Bugsee.setSecureRectangles([...regions.values()]);
+
+function MaskedRegion({ children }: { children: ReactNode }) {
+ const ref = useRef(null);
+ const [id] = useState(() => Symbol('MaskedRegion'));
+ const [masked, setMasked] = useState(false);
+ const mounted = useRef(true);
+ const measurement = useRef(0);
+
+ const publish = () => {
+ // Hide the content again until the new rectangle is published.
+ const generation = ++measurement.current;
+ setMasked(false);
+ ref.current?.measureInWindow((x, y, width, height) => {
+ // Ignore a late callback: after unmount, or superseded by a newer measurement.
+ if (!mounted.current || generation !== measurement.current) return;
+ regions.set(id, { x, y, width, height });
+ publishAll();
+ setMasked(true);
+ });
+ };
+
+ // Unmask when the component goes away, keeping the other regions.
+ useEffect(() => {
+ mounted.current = true;
+ return () => {
+ mounted.current = false;
+ regions.delete(id);
+ publishAll();
+ };
+ }, [id]);
+
+ return (
+
+ {/* Lay the content out while it is transparent, and show it once its region is published. */}
+ {children}
+
+ );
+}
```
-You also need to be aware of the orientation that can be changed while the app is running. Recreate rectangle after orientation change, if 'black box' on video does not cover all secure fields and elements.
+The example keeps its children transparent while their bounds are measured, and shows them once the rectangle is published, after every layout. A region is applied when a frame is captured, so content shown before then could appear unmasked in the first frames. It masks only content that is already laid out and does not move: content that mounts later without changing the wrapper's size, or that scrolls or animates, can leave the rectangle stale. For that, use `` or a blackout. The example keeps the regions of all its mounted instances together; any other code that calls `setSecureRectangles` replaces them, so give the call a single owner.
+
+| Argument | Type | Default | Description |
+| --- | --- | --- | --- |
+| `rectangles` | `SecureRectangle[]` | | `{ x, y, width, height }` objects, in React Native points, in the coordinates `measureInWindow` returns for a view in your app's root. An empty array clears the regions. |
+| `display` | `number` | `0` | The display the regions apply to; `0` is the main display. On iOS only display `0` is recorded. |
-Other methods of secure rectangles:
+- Each call **replaces** the regions the previous call set for that display. The regions are kept apart from those of mounted `` components: clearing them never uncovers a component, and a component unmounting never clears them.
+- The regions do not move with your layout. Measure again and call it again when the content moves.
+- The call is synchronous and returns nothing. The regions are read when the screen is captured: a few times a second on Android, with every captured frame on iOS.
+- The regions are always placed relative to your app's root view. A region measured inside a ``, whose `measureInWindow` coordinates are relative to the Modal, can land in the wrong place; use `` inside Modals.
+- The whole call throws `RangeError`, and changes nothing, when a rectangle has a non-finite coordinate, a negative width or height, or an edge too large for a 32-bit integer, or when `display` is not a non-negative integer. A bad rectangle is not skipped, because the rest being published would look like the region was masked.
+- Edges are rounded outward, so a region covers at most one unit more per edge than you asked for, never less: a pixel on Android, a point on iOS.
+- On Android, until the SDK has read where your app's root view is on the display (a fraction of a second after the first call), the regions are served as the whole display.
+- After a JavaScript reload, the regions the previous runtime set are cleared. Set them again from the new runtime.
-```javascript
-// Remove rect
-Bugsee.removeSecureRect(10, 10, 100, 100);
+## Blackout
-// Get all rectangles
-const rectangles = await Bugsee.getAllSecureRects();
+`Bugsee.startBlackout()` and `Bugsee.endBlackout()` bracket a flow during which everything that describes the screen is suppressed:
-// Remove all rectangles
-Bugsee.removeAllSecureRects();
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// Your own sensitive flow
+declare function presentRecoveryCodesScreen(): Promise;
+
+async function showRecoveryCodes(): Promise {
+ Bugsee.startBlackout();
+ try {
+ await presentRecoveryCodesScreen();
+ } finally {
+ Bugsee.endBlackout();
+ }
+}
```
+| Suppressed during a blackout | Recorded as usual |
+| --- | --- |
+| The video (black frames), the report screenshot (black), touch and gesture recording, and the view hierarchy. On iOS, also the keyboard and focus breadcrumbs. | Logs, network events, custom events and traces. |
+
+- `Bugsee.isBlackout()` resolves to the current state, so you can check that a blackout took effect.
+- **Before launch**: both platforms honor a blackout started before `Bugsee.launch`, and capture then starts blacked out. Call `startBlackout()` before `launch` to keep the first seconds of a session hidden. This does not cover Android [auto-launch](/sdk/react_native/expo#auto-launch-on-android): the SDK records from process start, before any JavaScript can call `startBlackout()`. On both platforms, `endBlackout()` before launch cancels it.
+- **On stop**: the platforms differ. On Android, `Bugsee.stop()` ends the blackout and the next launch starts without one; call `startBlackout()` again before launching to keep it. On iOS, only `endBlackout()` ends a blackout: it stays on across `stop` and the next `launch`. A `relaunch` keeps an active blackout on Android.
+- The SDK dispatches the `BlackoutStarted` and `BlackoutEnded` [lifecycle events](/sdk/react_native/lifecycle#lifecycle-events).
+
+For a full stop of all capture, logs and network included, use `Bugsee.stop()`; see [Lifecycle & status](/sdk/react_native/lifecycle).
-## Hiding keyboard (iOS only)
+## The view hierarchy
-In some cases you might want to prevent the keyboard from being captured on video (as well as touches). You can use the following method to achieve the desired effect.
+With your root component wrapped in [`Bugsee.wrap`](/sdk/react_native/installation#4-launch-bugsee), a report carries a view hierarchy of what was on screen. The tree the package builds holds component names, bounds and the `testID` and `nativeID` of host views. It holds no text content and no other props. Inside a ``, nodes are marked secure and carry no `testID` or `nativeID`.
+
+`Bugsee.captureViewHierarchy()` captures the view hierarchy at once, outside the SDK's normal pass. Turn view hierarchy capture off with `com.bugsee.option.capture.view-hierarchy`; during a blackout it is not captured.
+
+## Video and screenshot options
+
+| Option | Key | Default | Description |
+| --- | --- | --- | --- |
+| `captureVideo` | `com.bugsee.option.capture.video` | `true` | Record the screen. |
+| (no accessor) | `com.bugsee.option.capture.screenshot` | `true` | Attach a screenshot to each report, independently of the video. |
+| (no accessor) | `com.bugsee.option.capture.screenshot.scale` | `1` | Scale the screenshot down and back up, which destroys fine detail such as small text. `1` turns it off. |
+| (no accessor) | `com.bugsee.option.capture.video.scale` | `1` | Extra down-scaling of the recorded video, for example `0.5`, which also reduces detail. |
+| (no accessor) | `com.bugsee.option.capture.video.quality` | `VideoQuality.Default` | Quality of the encoded video. |
+| (no accessor) | `com.bugsee.option.capture.video.frame-rate` | `FrameRate.High` | How often frames are captured. |
+| (no accessor) | `com.bugsee.option.capture.view-hierarchy` | `true` | Capture the view hierarchy. |
+| `videoMode` (Android) | `com.bugsee.option.capture.video.mode` | `VideoMode.V2` | Android screen-capture strategy. |
+| (no accessor, Android) | `com.bugsee.option.capture.respect-flag-secure` | `true` | Blank windows with `FLAG_SECURE`. |
+| (no accessor, iOS) | `com.bugsee.option.capture.video.privacy-blur` | `true` | Blur transition frames instead of skipping them; off, the video freezes for the transition. |
+
+The defaults are the same on both platforms; read the values in effect with [`Bugsee.getLaunchOptions()`](/sdk/react_native/configuration#reading-the-effective-options). See [Configuration](/sdk/react_native/configuration) for setting keys without an accessor.
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+const options = createDefaultLaunchOptions();
+// Keep the video, but make small text unreadable in the screenshot and video
+options.setCustomOption('com.bugsee.option.capture.screenshot.scale', 0.5);
+options.setCustomOption('com.bugsee.option.capture.video.scale', 0.5);
+
+Bugsee.launch('', options);
+```
-```javascript
-// To let us capture keyboard
-Bugsee.setKeyboardVisibility(true);
+## Related pages
-// To prevent keyboard from being captured
-Bugsee.setKeyboardVisibility(false);
-```
\ No newline at end of file
+- [Privacy overview](/sdk/react_native/privacy/overview): every privacy control.
+- [Lifecycle & status](/sdk/react_native/lifecycle): stop, relaunch and lifecycle events.
+- [Configuration](/sdk/react_native/configuration): every launch option.
diff --git a/docs/sdk/react_native/release-notes.md b/docs/sdk/react_native/release-notes.md
index 2533006..35bcb9d 100644
--- a/docs/sdk/react_native/release-notes.md
+++ b/docs/sdk/react_native/release-notes.md
@@ -1,329 +1,91 @@
---
title: "Release notes"
-description: "Changelog for the Bugsee React Native SDK listing new features, bug fixes, and breaking changes for each released version."
-sidebar_position: 11
+description: "Release history for Bugsee React Native SDK 7.x (beta), with the native SDK versions each release is built on."
+sidebar_position: 23
slug: "/sdk/react_native/release-notes"
---
-## 6.0.5 (August 18 2026)
-- Internal improvements.
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
-## 6.0.4 (July 31 2026)
-- Feat: Updated native SDKs to their latest versions (Android: [6.0.4](/sdk/android/v6/release-notes/#604-june-22-2026), iOS: [6.3.1](/sdk/ios/release-notes/#631-july-31-2026))
+Release history for Bugsee React Native SDK 7.x: `@bugsee/react-native` and `@bugsee/react-native-feedback`, which are released together at the same version. Looking for the stable release? See the [6.x release notes](/sdk/react_native/v6/release-notes). Upgrading from 6.x? See the [migration guide](/sdk/react_native/migration).
-## 6.0.3 (June 23 2026)
-- Feat: Updated native SDKs to their latest versions (Android: [6.0.4](/sdk/android/v6/release-notes/#604-june-22-2026), iOS: [6.1.2](/sdk/ios/release-notes/#612-march-4-2026))
+Each release lists the native SDKs it is built on. Their own changes are in the native SDK release notes: [Android](/sdk/android/release-notes) and [iOS 7.x](/sdk/ios/v7/release-notes).
-## 6.0.2 (March 20 2026)
-- Feat: Updated native SDKs to their latest versions (Android: [6.0.2](/sdk/android/v6/release-notes/#602-march-11-2026), iOS: [6.1.2](/sdk/ios/release-notes/#612-march-4-2026))
+## 7.0.0-beta3 (October 20 2026)
-## 6.0.0 (March 6 2026)
-- Feat: Updated native SDKs to their latest versions (Android: [6.0.0](/sdk/android/v6/release-notes/#600-december-9-2025), iOS: [6.1.2](/sdk/ios/release-notes/#612-march-4-2026))
-- Breaking: \[iOS\] Minimum deployment target is iOS 12.0
-- Breaking: \[Android\] Bugsee SDK is now built with Android SDK version 35, hence requires compileSDKVersion 35
-- Breaking: \[Android\] AGP 8.6.0 or newer is now required
+Fixes the package's shell scripts, which 7.0.0-beta1 and 7.0.0-beta2 published without the executable bit.
-## 5.5.10 (November 18 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.9.1](/sdk/android/v6/release-notes/#591-september-29-2025), iOS: [5.5.9](/sdk/ios/release-notes/#559-november-17-2025))
+**Fixes**
-## 5.5.9 (October 15 2025)
-- Fix: \[Android\] In some scenarios, SDK may fail to launch
+- **Release builds work without a `chmod`.** `scripts/bugsee-xcode.sh` and `scripts/hermesc-preserve-js.sh` (and the two Node scripts next to them) are now published as executable. Android Release builds on macOS and Linux, and the bundle phase of a bare iOS app, no longer fail with "Permission denied". If you added the `chmod +x` workaround for 7.0.0-beta1 or 7.0.0-beta2, you can remove it after upgrading. The release process now packs with `npm pack` and fails if a file that is executable in the repository is not executable in the package.
+- `@bugsee/react-native-feedback` requires `@bugsee/react-native` `^7.0.0-beta3`.
-## 5.5.8 (October 15 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.9.1](/sdk/android/v6/release-notes/#591-september-29-2025), iOS: [5.5.8](/sdk/ios/release-notes/#558-august-21-2025))
+**Compatibility**
-## 5.5.7 (August 21 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.8.4](/sdk/android/v6/release-notes/#584-august-21-2025), iOS: [5.5.8](/sdk/ios/release-notes/#558-august-21-2025))
+- Android: Bugsee Android SDK 7.4.2, Bugsee Gradle plugin 4.0.8.
+- iOS: Bugsee iOS SDK 7.0.0-beta7.
+- `@bugsee/cli` 0.7.12.
-## 5.5.6 (August 8 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.8.3](/sdk/android/v6/release-notes/#583-august-8-2025), iOS: [5.5.7](/sdk/ios/release-notes/#557-august-1-2025))
+## 7.0.0-beta2 (October 19 2026)
-## 5.5.5 (August 7 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.8.2](/sdk/android/v6/release-notes/#582-august-7-2025), iOS: [5.5.7](/sdk/ios/release-notes/#557-august-1-2025))
+`launch` and `relaunch` take the options object as is.
-## 5.5.4 (June 12 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.7.5](/sdk/android/v6/release-notes/#575-june-8-2025), iOS: [5.5.6](/sdk/ios/release-notes/#556-march-25-2025))
-- Fix: \[Android\] In some configurations, application may crash on device with 16KB memory pages
+**Changes**
-## 5.5.3 (May 6 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.7.3](/sdk/android/v6/release-notes/#573-may-5-2025), iOS: [5.5.6](/sdk/ios/release-notes/#556-march-25-2025))
+- **No serialize step.** `Bugsee.launch(token, options)` and `Bugsee.relaunch(options)` accept the object from `createDefaultLaunchOptions()` directly. They still accept the plain map of `com.bugsee.option.*` keys, and `BugseeLaunchOptions.serialize(options)` still returns that map, so code written for `7.0.0-beta1` keeps working. See [Configuration](/sdk/react_native/configuration#two-ways-to-pass-options).
-## 5.5.2 (March 10 2025)
-- Fix: Build failure on Android
-- Feat: Updated native SDKs to their latest versions (Android: [5.7.2](/sdk/android/v6/release-notes/#572-march-17-2025), iOS: [5.5.6](/sdk/ios/release-notes/#556-march-25-2025))
+ ```ts
+ import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
-## 5.5.1 (March 10 2025)
-- Feat: Add option to enable native crashes interception in Android SDK (NdkCrashReport)
+ const options = createDefaultLaunchOptions();
+ options.captureLogs = true;
-## 5.5.0 (March 10 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.7.1](/sdk/android/v6/release-notes/#571-march-4-2025), iOS: [5.5.5](/sdk/ios/release-notes/#555-february-13-2025))
-- Feat: React Native "New architecture" support
+ // 7.0.0-beta1: Bugsee.launch(token, BugseeLaunchOptions.serialize(options));
+ Bugsee.launch(token, options);
+ ```
-## 5.4.3 (February 4 2025)
-- Feat: Updated native SDKs to their latest versions (Android: [5.6.5](/sdk/android/v6/release-notes/#565-february-3-2025), iOS: [5.5.4](/sdk/ios/release-notes/#554-january-27-2025))
-- Fix: \[Android\] Built-in UI shifts upwards in some scenarios on Android 15 (specifically, when hosting application itself is targeting Android 15, i.e. target SDK version is 35)
+- **npm tags.** The `latest` and `beta` tags both point at this beta, so a plain `yarn add @bugsee/react-native` installs it. Install with `@beta` to keep following betas once a stable 7.x release exists. See [Installation](/sdk/react_native/installation#1-add-the-package).
+- `@bugsee/react-native-feedback` requires `@bugsee/react-native` `^7.0.0-beta2`.
-## 5.4.2 (January 22 2025)
-- Fix: \[Android\] Network requests may not complete when custom networking libraries are used
+**Known issues**
-## 5.4.1 (January 14 2025)
-- Fix: \[Android\] Ensure Bugsee notification entry is displayed right away when runtime notification permission is granted from within application
+- The package's shell scripts (`scripts/bugsee-xcode.sh`, `scripts/hermesc-preserve-js.sh`) are published without the executable bit. Android Release builds on macOS and Linux, and the bundle phase of a bare iOS app, fail with "Permission denied" until you run `chmod +x node_modules/@bugsee/react-native/scripts/*.sh`. Fixed in 7.0.0-beta3. See [Symbolication: Android](/sdk/react_native/symbolication/android#1-javascript-source-maps) and [Symbolication: iOS](/sdk/react_native/symbolication/ios#1-the-bundle-phase-javascript-source-maps).
-## 5.4.0 (January 9 2025)
-- Feat: Updated native SDKs to their latest versions (Android: 5.6.1, iOS: 5.5.3)
-- Feat: Add support for bug reporting via screenshot gesture on Android
+**Compatibility**
-## 5.3.0 (September 12 2024)
-- Feat: Updated native SDKs to their latest versions (Android: 5.4.2, iOS: 5.3.2)
-- Feat: \[Android\] Add support for 16KB memory pages
-- Fix: \[Android\] Crash when bug is sent from built-in reporting UI after removing screenshot
+- Android: Bugsee Android SDK 7.4.2, Bugsee Gradle plugin 4.0.8.
+- iOS: Bugsee iOS SDK 7.0.0-beta7.
+- `@bugsee/cli` 0.7.12.
-## 5.2.0 (September 2 2024)
-- Feat: Updated native SDKs to their latest versions (Android: 5.3.1, iOS: 5.3.2)
+## 7.0.0-beta1 (October 19 2026)
-## 5.1.2 (May 08 2024)
-- Fix: \[Android\] Video may be absent on some devices with Unisoc chipsets
+The first public beta of the rewritten React Native SDK. `@bugsee/react-native` replaces `react-native-bugsee` 6.x: it is a new package with a new API, built on the 7.x native SDKs. See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
-## 5.1.1 (April 19 2024)
-- Fix: \[Android\] In some cases, video before FG->BG->FG transitions may be absent
-- Note: \[Android\] compileSdkVersion 34 and up is now required
+**Highlights**
-## 5.1.0 (April 19 2024)
-- Note: Broken release, please update to 5.1.1 or later
+- **Requirements**: React Native 0.81 or later with the New Architecture, Hermes, iOS 15.0 or later, Android API 21 or later. See [Overview](/sdk/react_native/overview#requirements).
+- **One package with the native SDKs.** Autolinking adds the Android SDK with its NDK and OkHttp modules; on iOS the SDK comes through the package's `Package.swift` (React Native 0.87 and later) or its podspec. See [Installation](/sdk/react_native/installation).
+- **One options namespace.** Both platforms read the same `com.bugsee.option.*` keys, set through `createDefaultLaunchOptions()` or a plain map. In this beta, `launch` and `relaunch` take the plain map, so an options object is passed as `BugseeLaunchOptions.serialize(options)`. See [Configuration](/sdk/react_native/configuration).
+- **Lifecycle**: `launch` and `relaunch` resolve to whether the SDK started, `attach()` for Android auto-launch, `getStatus()`, `onStatusChange()` and `onLifecycleEvent()` with named events. See [Lifecycle & status](/sdk/react_native/lifecycle).
+- **Crash and error reporting**: uncaught JavaScript errors, unhandled promise rejections, uncaught render errors through `Bugsee.wrap(App)`, native crashes, `logException(error, { domain })`, `logUnhandledException()` and ``. See [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting).
+- **Reports**: `showReportDialog()`, `upload()`, `createReport()` and a [report handler](/sdk/react_native/report-handler) that reads and changes reports and adds attachments.
+- **Data capture**: console logs with a native-side filter, network events with a filter and `addNetworkEvent()`, [breadcrumbs](/sdk/react_native/breadcrumbs), custom events and traces, attributes and a user identifier.
+- **Privacy**: ``, `setSecureRectangles()`, blackout, and filters for logs, network events and breadcrumbs. See [Privacy](/sdk/react_native/privacy/overview).
+- **Performance monitoring**: transactions and spans from JavaScript. See [Performance monitoring](/sdk/react_native/performance).
+- **Notification relay**: `notify()`. See [Notification relay](/sdk/react_native/notification-relay).
+- **Appearance**: one camelCase surface for the report UI colors. See [Appearance](/sdk/react_native/appearance).
+- **Feedback** in its own package, `@bugsee/react-native-feedback`. See [Feedback](/sdk/react_native/feedback).
+- **Expo config plugin** for prebuild: the Bugsee Gradle plugin, the source-map hooks, the dSYM post-action, Android auto-launch and a custom endpoint. See [Expo](/sdk/react_native/expo).
+- **Symbolication**: JavaScript source maps matched by debug ID, the Android R8 mapping and native symbols through the Bugsee Gradle plugin, and iOS dSYMs, optionally with React Native's own. See [Symbolication](/sdk/react_native/symbolication/overview).
-## 5.0.4 (April 18 2024)
-- Fix: Sourcemaps were not uploaded properly in some cases for Android
+**Known issues**
-## 5.0.3 (April 11 2024)
-- Feat: Updated native SDKs to their latest versions (Android: 4.2.4, iOS: 5.0.2)
+- The package's shell scripts (`scripts/bugsee-xcode.sh`, `scripts/hermesc-preserve-js.sh`) are published without the executable bit. Android Release builds on macOS and Linux, and the bundle phase of a bare iOS app, fail with "Permission denied" until you run `chmod +x node_modules/@bugsee/react-native/scripts/*.sh`. Fixed in 7.0.0-beta3. See [Symbolication: Android](/sdk/react_native/symbolication/android#1-javascript-source-maps) and [Symbolication: iOS](/sdk/react_native/symbolication/ios#1-the-bundle-phase-javascript-source-maps).
-## 5.0.2 (April 2 2024)
-- Fix: "handleRejections" launch option may not be respected in some cases
+**Compatibility**
-## 5.0.1 (March 21 2024)
-- Feat: Updated native SDKs to their latest versions (Android: 4.2.4, iOS: 5.0.0)
-
-## 5.0.0 (December 25 2023)
-- Feat: Updated native SDKs to their latest versions (Android: 4.2.1, iOS: 5.0.0)
-- Breaking: \[iOS\] Bitcode is not present in the resulting binaries any more
-
-## 4.1.0 (December 6 2023)
-- Feat: Updated native SDKs to their latest versions (Android: 4.2.1, iOS: 4.1.0)
-
-## 4.0.0 (October 2 2023)
-- Feat: Updated native SDKs to their latest versions (Android: [4.0.1](/sdk/android/v6/release-notes/#401-september-30-2023), iOS: [4.0.1](/sdk/ios/release-notes/#401-september-30-2023))
-- Breaking: Changes for the underlying SDKs: [Android](/sdk/android/v6/release-notes/#401-september-30-2023) and [iOS](/sdk/ios/release-notes/#401-september-30-2023).
-
-## 3.2.0 (September 1 2023)
-- Feat: Updated native SDKs to their latest versions (Android: 3.10.0, iOS: 3.8.0)
-- Feat: Add new API to manually trigger view hierarchy capturing. Multiple view hierarchies support.
-
-## 3.1.3 (August 4 2023)
-- Feat: Updated underlying Android SDKs to their latest version (3.8.3)
-- Fix: \[Android\] Deadlock in some specific scenario when application comes to foreground
-
-## 3.1.2 (July 12 2023)
-- Feat: Updated native SDKs to their latest versions (Android: 3.8.2, iOS: 3.7.1)
-- Fix: \[Android\] In some circumstances crashes may not be reported
-
-## 3.1.1 (June 20 2023)
-- Fix: Issue with logException() on iOS
-
-## 3.1.0 (June 12 2023)
-- Fix: Properly respect MonitorNetwork option during relaunch
-
-## 3.0.10 (February 26 2023)
-- Feature: Update native SDKs to the latest versions (Android: 3.4.0, iOS: 3.3.3)
-
-## 3.0.9 (February 14 2023)
-- Fix: Crash when attachment data contained non-text value (e.g. object, array, etc)
-
-## 3.0.8 (January 26 2023)
-- Feature: Update native SDKs to the latest versions (Android: 3.4.0, iOS: 3.3.2)
-- Fix: \[Android\] Video was disabled on some Samsung devices due to the restrictive internal checks
-
-## 3.0.7 (January 24 2023)
-- Fix: Workaround for a bug in React Native build script which caused source maps collection failure
-
-## 3.0.6 (January 23 2023)
-- Fix: Incorrect selector in iOS bridging module may cause build errors
-
-## 3.0.5 (January 20 2023)
-- Feature: Update native SDKs to the latest versions (Android: 3.3.0, iOS: 3.3.2)
-
-## 3.0.4 (December 7 2022)
-- Fix: Some async exceptions were not properly handled which caused missing video and data in the consequent bug/error/crash reports
-- Feature: Update native SDKs to the latest versions (Android: 3.1.0, iOS: 3.3.1)
-
-## 3.0.3 (November 28 2022)
-- Feature: Update native SDKs to the latest versions (Android: 3.0.2, iOS: 3.2.1)
-
-## 3.0.2 (October 5 2022)
-- Feature: Add fallbacks for Gradle properties (compileSdkVersion, targetSdkVersion, buildToolsVersion)
-
-## 3.0.1 (October 4 2022)
-- Fix: Messages sent to Bugsee.log() may not be registered properly
-
-## 3.0.0 (September 19 2022)
-- Feature: Update native SDKs to the latest versions (Android: 3.0.0, iOS: 3.0.0)
-- Feature: Reworked debugging information uploading mechanism (source maps uploading) which is now fully automatic
-- Note: Please refer to the underlying SDKs release notes to get the detailed list of changes: [Android](/sdk/android/v6/release-notes/#300-august-19-2022) / [iOS](/sdk/ios/release-notes/#300-september-1-2022)
-
-## 2.10.3 (June 1 2022)
-- Feature: Updated native Android SDKs to their latest versions. Several race conditions are fixed
-
-## 2.10.2 (May 11 2022)
-- Feature: Updated native Android/iOS SDKs to their latest versions
-
-## 2.10.1 (April 28 2022)
-- Feature: Updated native Android/iOS SDKs to their latest versions
-
-## 2.10.0 (April 14 2022)
-- Feature: Updated native Android/iOS SDKs to their latest versions
-
-## 2.9.1 (March 22 2022)
-- Fix: Some network events were not captured properly when network filter was set (on Android)
-
-## 2.9.0 (March 16 2022)
-- Feature: Updated native iOS SDKs to their latest version
-- Feature: Clean script is not required any more for iOS project
-
-## 2.8.0 (February 04 2022)
-- Feature: Updated native iOS SDKs to their latest version
-- Feature: iOS SDK is not bundled within the NPM package any more, but rather is fetched via CocoaPods
-
-## 2.7.0 (January 26 2022)
-- Feature: Updated native SDKs to its newer versions.
-- Fix \[iOS\]: Crash during video capture in some specific conditions
-
-## 2.6.1 (November 12 2021)
-- Feature: Improve exception information handling for better symbolication of JS call stacks
-
-## 2.6.0 (October 4 2021)
-- Feature: Updated native Android SDKs to their latest versions. They include full support for iOS 15 and Android 12
-
-## 2.5.1 (August 12 2021)
-- Feature: Automatically generate stack trace when non-Error instance is supplied to logException
-
-## 2.5.0 (August 3 2021)
-- Feature: Updated native Android SDKs to their latest versions. It includes many updates to embedded dependencies to mitigate the NonSdkApi warnings and errors.
-
-## 2.4.6 (June 18 2021)
-- Fix: Add missing reporting UI controlling flags to launch options
-
-## 2.4.5 (June 17 2021)
-- Fix: In some rare cases launch options may not be sent to the underlying SDKs correctly
-
-## 2.4.4 (June 13 2021)
-- Fix: Properly handle symbolication result from built-in symbolicator
-
-## 2.4.3 (June 8 2021)
-- Feature: Updated native SDKs to their latest versions
-- Feature: Add video fallback mode launch option for Android
-
-## 2.4.2 (May 17 2021)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.4.1 (April 20 2021)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.4.0 (February 24 2021)
-- Feature: Updated native SDKs to their latest versions
-- Feature: Improve autolinking support
-
-## 2.3.8 (February 10 2021)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.3.7 (November 10 2020)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.3.6 (August 31 2020)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.3.5 (August 11 2020)
-- Feature: Updated native Android SDK to its latest version \[1.19.0\]
-
-## 2.3.4 (June 9 2020)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.3.3 (April 14 2020)
-- Fix: Rare crash when using ref statements and node is not found
-
-## 2.3.2 (June 7 2020)
-- Feature: Updated native SDKs to their latest versions
-
-## 2.3.1 (April 7 2020)
-- Fix: Update native SDK, to disable on-device symbolication by default to prevent application crash \[iOS\]
-
-## 2.2.2 (February 25 2020)
-- Feature: Update native SDKs
-
-## 2.2.1 (June 27 2019)
-- Fix: Memory leak in report controller (iOS)
-
-## 2.2.0 (June 21 2019)
-- Feature: Add option to control bluetooth state monitoring (iOS)
-- Feature: Add support for lifecycle events
-
-## 2.0.14 (Mar 27 2019)
-- Fix: Update iOS SDK to the latest version to fix a rare crash during view hierarchy capturing
-
-## 2.0.13 (Mar 15 2019)
-- Fix: Updated Android SDK to the latest version containing the fix for touch interception
-
-## 2.0.12 (Mar 11 2019)
-- Feature: Expose methods to trigger JS and native crashes manually
-
-## 2.0.9 - 2.0.11 (Mar 4 2019)
-- Fix: Correctly define and use Launch options in index.ts file
-
-## 2.0.8 (Jan 29 2019)
-- Fix: Properly check for Podfile presence during linking to prevent failure
-
-## 2.0.1 - 2.0.7 (Jan 14 2019)
-- Fix: Duplicate iOS crash/error reports
-- Fix: Some crashes do not merge properly
-- Fix: Fix automatic Bugsee iOS SDK module linking (via 'react-native link')
-- Other minor improvements
-
-## 2.0.1 (Jan 1 2019)
-- Fix: Update iOS SDK to 1.19.1 to prevent app crashing in some cases. For more info look [here](/sdk/ios/release-notes/)
-
-## 2.0.0 (December 26 2018)
-- Feature: Much easier installation and initialization (via 'react-native link')
-- Feature: New module design. Now everything can be controlled from JS
-- Feature: Add support for custom attachments
-- Feature: New exceptions capturing mechanism
-
-## 1.1.0 (May 31 2018)
-- Feature: Network and console logs filters (privacy)
-- Feature: Enable/disable keyboard capture (privacy, iOS-only)
-- Feature: Secure rectangles. Allows explicitly specify area which must be concealed from recording.
-- Feature: Source maps. Added support for source maps to properly symbolicate stack traces for minified JS sources.
-
-## 1.0.8 (Aug 31 2017)
-- Maintenance and bug-fix release.
-
-## 1.0.7 (Apr 11 2017)
-- Maintenance and bug-fix release.
-
-## 1.0.6 (Mar 7 2017)
-- Maintenance and bug-fix release.
-
-## 1.0.5 (Mar 4 2017)
-- Maintenance and bug-fix release.
-
-## 1.0.4 (Mar 4 2017)
-- Maintenance and bug-fix release.
-
-## 1.0.3 (Dec 16 2016)
-- Maintenance and bug-fix release.
-
-## 1.0.2 (Oct 13 2016)
-- Maintenance and bug-fix release.
-
-## 1.0.1 (Sep 14 2016)
-- Maintenance and bug-fix release.
-
-## 1.0.0 (Sep 14 2016)
-- Initial release
\ No newline at end of file
+- Android: Bugsee Android SDK 7.4.2, Bugsee Gradle plugin 4.0.8.
+- iOS: Bugsee iOS SDK 7.0.0-beta7, itself a beta.
+- `@bugsee/cli` 0.7.12.
diff --git a/docs/sdk/react_native/report-handler.mdx b/docs/sdk/react_native/report-handler.mdx
new file mode 100644
index 0000000..18999e4
--- /dev/null
+++ b/docs/sdk/react_native/report-handler.mdx
@@ -0,0 +1,268 @@
+---
+title: "Report handler"
+description: "Inspect, enrich or redact every report before Bugsee React Native SDK 7.x sends it: setReportHandler, its two callbacks, the report object, deadlines, and attachments."
+sidebar_position: 6
+slug: "/sdk/react_native/report-handler"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+A **report handler** is the one place to inspect or change a report before Bugsee sends it. It sees every kind of report that reaches JavaScript: bug reports from the dialog or from `upload`, error reports, and crash reports when the SDK hands them to JavaScript (see [Async callbacks and deadlines](#async-callbacks-and-deadlines)). That makes it the hook for anything that must apply to all of them: labels, attributes, a severity rule, a config snapshot as an attachment, or redacting text.
+
+```ts
+import Bugsee, { createDefaultLaunchOptions } from '@bugsee/react-native';
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ await report.setLabels(['beta-build']);
+ },
+});
+
+Bugsee.launch('', createDefaultLaunchOptions());
+```
+
+## Install it before launch
+
+Call `Bugsee.setReportHandler(handler)` **before** `Bugsee.launch`. During launch the SDK recovers reports from the previous run, such as a crash, and a handler installed afterward misses them.
+
+Under Android auto-launch, where you call [`Bugsee.attach()`](/sdk/react_native/lifecycle#attach-to-a-running-sdk) instead of `launch`, the SDK recovers those reports before any JavaScript runs, so the handler cannot see them.
+
+The handler lives in the JavaScript runtime. When the runtime reloads (a development reload, for example), every callback still outstanding is completed at once, and the reports go on without it; install the handler again in the new runtime.
+
+There is one handler at a time. A later call replaces it, and `setReportHandler(null)` stops delivery; a later call can turn it back on. A replacement takes effect from the next callback: a callback already running keeps the handler it started with.
+
+The handler is any object with one or both callbacks. A class instance works too: each callback is called with the handler as `this`.
+
+## The two callbacks
+
+| Callback | When it runs | Delivered |
+| --- | --- | --- |
+| `onBeforeReportCreated(report)` | Before the report is built. | **At most once** per report, and may be skipped: a crash recovered at launch, for one, can go straight to `onAfterReportCreated`. |
+| `onAfterReportCreated(report)` | After the report is built, before it is sent. | **At least once**: it can run more than once for the same report. |
+
+Both are optional, and a phase you leave out is not delivered to JavaScript at all.
+
+Because `onAfterReportCreated` can run more than once, make it **idempotent**: running it twice must leave the report as running it once would. Set values rather than append them (`setLabels`, `setAttribute`), and check `getAttachmentNames()` before you add an attachment an earlier run may already have added.
+
+### Reports from your own calls
+
+| Call | `onBeforeReportCreated` | `onAfterReportCreated` |
+| --- | --- | --- |
+| `showReportDialog` | Before the dialog opens, so it does not see what the user types. | After the report is built from what the user sent. |
+| `upload`, `logException`, automatic error capture | Before the report is built. | After it is built. |
+| Crashes | May be skipped. | Depends on the platform and the kind of crash; see [Async callbacks and deadlines](#async-callbacks-and-deadlines). |
+| `createReport` on Android | Inside `createReport()`. | At the created report's `upload()`. |
+| `createReport` on iOS | At `upload()`. | At `upload()`. Both run after the created report's fields are copied, so a handler `setLabels` replaces the labels you set. |
+
+To act on what a user typed into the dialog, such as redacting it, use `onAfterReportCreated`.
+
+## Async callbacks and deadlines
+
+A callback can be `async`, or return a promise. The SDK waits for it to settle before it moves on with the report, up to a **deadline** the SDK sets:
+
+| Report | Android | iOS |
+| --- | --- | --- |
+| A live report, raised by the running app | 25 seconds | 25 seconds |
+| A report recovered at launch (a crash from the previous run) | Java crash, with the SDK launched from JavaScript: 25 seconds. Native (NDK) crash, and the SDK's early recovery at startup: the handler is **not called**. | 2.5 seconds, best-effort: changes land only until the SDK has assembled the report. |
+| A report raised while the process is terminating | Not called. | Not called.\* |
+
+\* No report is raised on a terminating process on iOS today; if one ever is, it goes on without calling the handler.
+
+On Android, a lower `com.bugsee.option.config.report-handler-callback-timeout` (seconds) lowers the live deadline to one second under that value; it never raises it above 25 seconds. If that leaves less than a second, the handler is not called. The option is Android only (see [Platform-only keys](/sdk/react_native/configuration#platform-only-keys)): on iOS the deadlines in the table are fixed, and no option changes them.
+
+Every report method is asynchronous and must finish **before** the callback settles. Await each call, or return the promise:
+
+```ts
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ await report.setAttribute('screen', currentScreenName());
+ // Not awaited: nothing guarantees it lands before the handle dies,
+ // and a rejection would go unhandled.
+ // report.setSeverity(IssueSeverity.Critical);
+ },
+});
+```
+
+Once the callback has settled, or its deadline has passed, the report handle is dead: every further call on it rejects with `E_REPORT_HANDLE_DEAD`, and nothing more reaches the report. The deadline is the SDK's own; you cannot extend it.
+
+Keep work that runs for recovered reports short: async I/O in `onAfterReportCreated` that completes in time on an Android Java crash can miss the iOS recovery window, and an Android native crash never reaches the handler at all.
+
+### If your callback throws
+
+A callback that throws or rejects does not lose the report. The SDK logs `[Bugsee] report handler threw` with the error's name to the console, and the report goes on. Changes that already reached the report before the throw are kept.
+
+There is no way to drop a report from the handler. To keep data out of one, redact it: clear the text and attributes you do not want sent.
+
+## The report object
+
+Each callback receives a `BugseeReport`, a live handle on the report:
+
+| Member | Type | Description |
+| --- | --- | --- |
+| `id` | `string` | The report's ID. |
+| `type` | `ReportType` | `'bug'`, `'crash'` or `'error'`. Treat it as an open set: a newer native SDK can add kinds. |
+
+The other members return promises:
+
+| Area | Methods |
+| --- | --- |
+| Read everything | `read()` |
+| Text | `getSummary()`, `setSummary(value)`, `getDescription()`, `setDescription(value)` |
+| Severity | `getSeverity()`, `setSeverity(value)` |
+| Labels | `getLabels()`, `setLabels(labels)` |
+| Attributes | `getAttributes()`, `setAttribute(name, value)`, `clearAttributes()` |
+| Screenshots | `getScreenshotDisplayIds()` |
+| Attachments | `getAttachmentNames()`, `addFileAttachment(path, options)`, `addDataAttachment(base64, options)` |
+| Several changes at once | `update(patch)` |
+
+Two deliveries of the same report get two separate handles, each with its own deadline.
+
+### Reading a report
+
+`read()` returns a `BugseeReportSnapshot` in one call; each getter is a shortcut for one of its fields:
+
+| Field | Type | Notes |
+| --- | --- | --- |
+| `summary` | `string \| undefined` | |
+| `description` | `string \| undefined` | |
+| `severity` | `IssueSeverity \| undefined` | `undefined` when the report has no severity set (iOS reports `0` for that), or the value is outside 1 to 5. |
+| `labels` | `string[]` | |
+| `attributes` | `Record` | This report's attributes. |
+| `screenshotDisplayIds` | `number[]` | The displays the report has a screenshot of, in ascending order. |
+| `attachmentNames` | `string[]` | |
+
+### Changing a report
+
+The setters each change one field. `update(patch)` changes several in one call:
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ await report.update({
+ summary: 'Checkout frozen',
+ description: null, // clears the description
+ severity: IssueSeverity.Critical,
+ labels: ['checkout', 'payments'], // replaces the whole list
+ clearAttributes: true, // applied before `attributes`
+ attributes: { cartSize: 3, coupon: null }, // null removes that attribute
+ });
+ },
+});
+```
+
+A `ReportPatch` has these keys, all optional:
+
+| Key | Type | Effect |
+| --- | --- | --- |
+| `summary` | `string \| null` | Sets the summary; `null` clears it. |
+| `description` | `string \| null` | Sets the description; `null` clears it. |
+| `severity` | `IssueSeverity` | An integer from 1 to 5. |
+| `labels` | `readonly string[]` | **Replaces** the report's labels. There is no append. |
+| `clearAttributes` | `true` | Removes every attribute of the report, before `attributes` is applied. |
+| `attributes` | `Record` | Sets each attribute; `null` removes that one. Names must be non-empty; numbers must be finite. |
+
+A patch is **all or nothing**. It is checked in full first, and if any key is unknown or any value is invalid, nothing is applied and the call rejects with `E_REPORT_BAD_ARGUMENT`. A misspelled key fails the patch rather than being ignored. The single-field setters follow the same rules.
+
+Attributes set here apply to this report only. For attributes that go with every report, use [`Bugsee.setAttribute`](/sdk/react_native/user-session-data).
+
+## Attachments
+
+```ts
+report.addFileAttachment(path, { name, mimeType?, move? });
+report.addDataAttachment(base64, { name, mimeType? });
+```
+
+- **`addFileAttachment`** attaches a file. `path` is a `file://` URL (the prefix is removed and the rest percent-decoded) or a plain file path, used as is. The file is captured when it is added. With `move: true` the SDK takes the file instead of copying it, so it is no longer at `path` afterward.
+- **`addDataAttachment`** attaches bytes, given as a base64 string: its length a multiple of 4, using `A-Z`, `a-z`, `0-9`, `+`, `/` and `=` padding only.
+- `name` is required and must be non-empty. `mimeType` is optional.
+- A report from the handler takes up to **1000** attachments, on both platforms. When an attachment is declined, the call rejects with `E_REPORT_ATTACHMENT_REJECTED`.
+
+Keep attachments small: they travel with the report on the user's connection. Reports you build with `createReport` have their own, lower limit on iOS; see [Bug reporting](/sdk/react_native/manual/bug-reporting#platform-differences).
+
+## Errors
+
+Report methods reject with a `BugseeReportError` for the codes below; match on its `code`. Any other failure, such as an unexpected internal fault, rejects with an ordinary error, so rethrow what you do not match.
+
+| `ReportErrorCode` | `code` | Meaning |
+| --- | --- | --- |
+| `HandleDead` | `E_REPORT_HANDLE_DEAD` | The callback already settled, or its deadline passed. |
+| `AttachmentRejected` | `E_REPORT_ATTACHMENT_REJECTED` | The attachment was declined. |
+| `BadArgument` | `E_REPORT_BAD_ARGUMENT` | An argument or patch failed validation; nothing was applied. |
+
+## Examples
+
+### Labels and an attachment on every report
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// React Native's default TypeScript config has no DOM types, so declare the
+// global btoa the runtime provides (or use a base64 library).
+declare function btoa(data: string): string;
+
+const CONFIG_ATTACHMENT = 'config.json';
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ // setLabels replaces the list, so a second run gives the same result.
+ const labels = await report.getLabels();
+ await report.setLabels([...new Set([...labels, 'beta-build'])]);
+
+ // Add the attachment only if an earlier run has not.
+ const names = await report.getAttachmentNames();
+ if (!names.includes(CONFIG_ATTACHMENT)) {
+ await report.addDataAttachment(btoa(JSON.stringify(currentConfig())), {
+ name: CONFIG_ATTACHMENT,
+ mimeType: 'application/json',
+ });
+ }
+ },
+});
+```
+
+`btoa` encodes only Latin-1 text; encode other text to bytes first, or use a base64 library.
+
+### Raise the severity of crashes in one area
+
+```ts
+import Bugsee, { IssueSeverity } from '@bugsee/react-native';
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ if (report.type === 'crash' && (await report.getLabels()).includes('payments')) {
+ await report.setSeverity(IssueSeverity.Blocker);
+ }
+ },
+});
+```
+
+### Redact card numbers from user text
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+const CARD_NUMBER = /\b\d{16}\b/g;
+
+Bugsee.setReportHandler({
+ onAfterReportCreated: async (report) => {
+ const { summary, description } = await report.read();
+ await report.update({
+ summary: summary?.replace(CARD_NUMBER, '[CARD]') ?? null,
+ description: description?.replace(CARD_NUMBER, '[CARD]') ?? null,
+ });
+ },
+});
+```
+
+The redaction runs in `onAfterReportCreated` because that is where a dialog report carries what the user typed.
+
+## Related pages
+
+- [Bug reporting](/sdk/react_native/manual/bug-reporting): the report dialog, `upload` and `createReport`.
+- [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting): which errors become reports.
+- [User & session data](/sdk/react_native/user-session-data): attributes for every report.
+- [Privacy: Report](/sdk/react_native/privacy/report): what a report sends, and how to limit it.
diff --git a/docs/sdk/react_native/symbolication/android.mdx b/docs/sdk/react_native/symbolication/android.mdx
new file mode 100644
index 0000000..8c0db4d
--- /dev/null
+++ b/docs/sdk/react_native/symbolication/android.mdx
@@ -0,0 +1,219 @@
+---
+title: "Symbolication: Android"
+description: "Setting up a bare React Native 7.x Android app to upload JavaScript source maps, the R8 mapping and native symbols for each Release build, and fixing what goes wrong."
+sidebar_position: 2
+slug: "/sdk/react_native/symbolication/android"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+An Android Release build needs three uploads for readable reports: the JavaScript source map, the R8/ProGuard mapping, and the native symbols. Autolinking cannot set any of them up, because they are build edits, not dependencies. [Symbolication overview](/sdk/react_native/symbolication/overview) explains what each one is for.
+
+This page is for a bare app, where you own `android/`. With Expo prebuild, the [config plugin](/sdk/react_native/expo) writes the same edits on each prebuild; see [Expo prebuild](#expo-prebuild).
+
+| What | Edit | Needs the Bugsee Gradle plugin |
+| --- | --- | --- |
+| JavaScript source map | `react.hermesCommand` and `apply from: …/bugsee-sourcemaps.gradle` in `android/app/build.gradle` | No |
+| R8/ProGuard mapping | Apply `com.bugsee.android.gradle` | Yes |
+| Native symbols | The plugin, `plugin.ndk.enabled=true`, and the NDK module | Yes |
+
+All three read the app token from `android/bugsee.properties`.
+
+## 1. JavaScript source maps
+
+Release builds give the Hermes bundle a debug ID and upload its composed source map, so JavaScript frames resolve. This needs two edits in `android/app/build.gradle` and no Gradle plugin.
+
+Add these lines below the `apply plugin:` lines at the top of the file (the `react { }` block needs `com.facebook.react` applied first, and section 2 uses `bugseeDir` too). Resolve the package through node, as React Native's own template resolves `react-native`, so a hoisted or nested install works too:
+
+```groovy title="android/app/build.gradle"
+def bugseeDir = new File(["node", "--print", "require.resolve('@bugsee/react-native/package.json')"]
+ .execute(null, rootDir).text.trim()).getParentFile()
+
+react {
+ // Keeps the JS aside before hermesc compiles it, so the debug ID can reach the bytecode.
+ // Keep it on one line: tools that apply this snippet read it as one.
+ hermesCommand = new File(new File(bugseeDir, "scripts"), System.getProperty("os.name").startsWith("Windows") ? "hermesc-preserve-js.cmd" : "hermesc-preserve-js.sh").absolutePath
+}
+
+// At the end of the file. Applying it twice is harmless.
+apply from: new File(new File(bugseeDir, "scripts"), "bugsee-sourcemaps.gradle")
+```
+
+What the two edits do:
+
+- **`hermesCommand`** runs `hermesc` through the package's wrapper, which keeps a copy of the JavaScript before `hermesc` compiles it. React Native runs this command through `cmd` on Windows, which cannot run a shell script, so Windows gets the `.cmd` launcher and macOS and Linux the `.sh`. The operating system is checked when Gradle configures the build, so one `build.gradle` works on all three. Both launchers run `node`, which must be on the `PATH`, as React Native's own bundling already requires.
+- **`bugsee-sourcemaps.gradle`** hooks every `createBundleJsAndAssets` task. After the bundle is built, it injects the debug ID into the composed map and the kept JavaScript, compiles that JavaScript to bytecode again so the ID is in what ships, and uploads the map with `@bugsee/cli`.
+
+If Hermes compiles a bundle without going through the wrapper, the bundle task fails instead of shipping a Release without a debug ID. See [Troubleshooting](#troubleshooting).
+
+:::caution[7.0.0-beta1 and 7.0.0-beta2: scripts without the executable bit]
+In 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) the package's shell scripts are published without the executable bit (mode 644). React Native runs `hermesCommand` directly, so on macOS and Linux the Release bundle task fails with "Permission denied" on `hermesc-preserve-js.sh`. Windows, which uses the `.cmd` launcher, is not affected. Expo apps are affected too, since the config plugin writes the same `hermesCommand`. Make the scripts executable after every install, for example from a `postinstall` script in your app's `package.json`:
+
+```json title="package.json"
+{
+ "scripts": {
+ "postinstall": "chmod +x node_modules/@bugsee/react-native/scripts/*.sh"
+ }
+}
+```
+
+Adjust the path if the package is installed elsewhere, for example hoisted to a monorepo root. A CI job that installs with `--ignore-scripts` needs the same `chmod` as its own step.
+:::
+
+### Upload settings
+
+- **Token.** `app_token` in `android/bugsee.properties` (next to `android/build.gradle`), then the `BUGSEE_APP_TOKEN` environment variable, then `BUGSEE_TOKEN_ANDROID`. Without a real token the upload is skipped with one line in the build log.
+- **Version and build number.** The variant's own `versionName` and `versionCode`, flavors included. Without them the upload is skipped.
+- **Endpoint.** `plugin.endpoint` in `android/bugsee.properties`, then `BUGSEE_ENDPOINT`. Unset, the map goes to Bugsee's production API.
+- **Turning it off.** Pass `-PbugseeUploadSourcemaps=false`, set `bugseeUploadSourcemaps=false` in `android/gradle.properties`, or export `BUGSEE_UPLOAD_SOURCEMAPS=false`. The debug ID is still injected; only the upload is skipped.
+- **Failures.** A failed upload prints a warning and the build continues.
+
+React Native's default `hermesFlags` include `-output-source-map`. If you set your own flags, keep it: without it React Native composes no source map, and the hook injects no debug ID and uploads nothing.
+
+:::note
+The hook has not yet been verified with Gradle's configuration cache.
+:::
+
+## 2. The Bugsee Gradle plugin
+
+The Bugsee Gradle plugin (`com.bugsee.android.gradle`) uploads the R8/ProGuard mapping, the native symbols and the build info of each Release build. It is a Gradle plugin, so autolinking cannot add it.
+
+It is also what records `fetch` and `XMLHttpRequest` on Android: React Native sends them through OkHttp, and the plugin is what lets the SDK record OkHttp traffic. Without the plugin, those requests are not recorded on Android; see [Network events](/sdk/react_native/network).
+
+Use the plugin version the package is built against: `android.gradlePlugin` in `node_modules/@bugsee/react-native/native-versions.json`, which is **4.0.8** for `7.0.0-beta3`. Its requirements (Android Gradle Plugin and Gradle versions) are on [Gradle plugin requirements](/sdk/android/gradle-plugin/requirements).
+
+**`android/settings.gradle`**: the plugin is published to Maven Central, which Gradle does not search for plugins unless told to:
+
+```groovy title="android/settings.gradle"
+pluginManagement {
+ includeBuild("../node_modules/@react-native/gradle-plugin")
+ repositories {
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ }
+}
+```
+
+**`android/build.gradle`**: declare the plugin, above `apply plugin: "com.facebook.react.rootproject"`. Declare it here with `apply false` and apply it in the app module: applied to the root project, it fails the configuration, because it hangs its tasks off an Android variant.
+
+```groovy title="android/build.gradle"
+plugins {
+ id 'com.bugsee.android.gradle' version '4.0.8' apply false
+}
+```
+
+**`android/app/build.gradle`**: apply it, and add the NDK module at the SDK version the package pins:
+
+```groovy title="android/app/build.gradle"
+apply plugin: "com.android.application"
+apply plugin: "org.jetbrains.kotlin.android"
+apply plugin: "com.facebook.react"
+apply plugin: "com.bugsee.android.gradle"
+
+// bugseeDir as in "JavaScript source maps" above.
+def bugseeVersions = new groovy.json.JsonSlurper().parse(new File(bugseeDir, "native-versions.json"))
+
+dependencies {
+ implementation "com.bugsee:bugsee-android-ndk:${bugseeVersions.android.sdk}"
+}
+```
+
+The package already depends on `bugsee-android-ndk`, but not as a direct dependency of your `:app` module. With `plugin.ndk.enabled=true`, the Gradle plugin adds the NDK module itself, on its own version range. Declaring it at the package's pin keeps it at the SDK version the package was built against.
+
+**`android/bugsee.properties`**, next to `android/build.gradle` (the root project, not `android/app/`):
+
+```properties title="android/bugsee.properties"
+app_token=
+plugin.ndk.enabled=true
+```
+
+The token key is the unprefixed `app_token`, not `plugin.appToken`. Keep this file out of version control if the token is private, and write it from your CI secrets. Every other plugin setting, and its DSL form, is on [Gradle plugin configuration](/sdk/android/gradle-plugin/configuration).
+
+There is a mapping to upload only when R8 minifies the build (`minifyEnabled true`). React Native's app template ships with it off (`enableProguardInReleaseBuilds = false`); then your Java and Kotlin frames are not renamed and need no mapping, while JavaScript and native frames still need their uploads.
+
+The plugin's upload tasks, `uploadBugseeMapping`, `uploadBugseeNative` and the build-info tasks, finalize `assemble` and `bundle`. [Gradle plugin builds & uploads](/sdk/android/gradle-plugin/builds-upload) lists them, with what build info sends.
+
+## 3. Native symbols
+
+With `plugin.ndk.enabled=true`, each Release build's `uploadBugseeNative` task uploads native symbols. Gradle plugin 4.0.8 reads them from the **unstripped** libraries that the Android Gradle Plugin leaves in `build/intermediates/merged_native_libs/`, keyed by GNU build ID. That makes them independent of `ndk.debugSymbolLevel`:
+
+- Every library that still has its debug info is uploaded with it, so crash frames get function names and `file:line`. That covers your own native code, and React Native's `libreactnative.so`, which the Maven `react-android` artifact ships with full debug info.
+- Libraries that ship stripped (Hermes's `libhermesvm.so` from Maven, the Bugsee SDK's own) get their symbol table: function names only.
+- An unchanged prebuilt library, such as `libreactnative.so` or `libc++_shared.so`, has the same build ID in every release, and the server keeps one copy.
+- The symbols are a build artifact: nothing is added to the APK or AAB.
+
+So `ndk { debugSymbolLevel … }` is your own choice, for what Google Play receives. Bugsee does not need it.
+
+The plugin uses its own copy of the Bugsee CLI. If you pin that CLI yourself (`plugin.cliPath` or `plugin.cliVersion`), use 0.8.1 or later: older CLIs do not read `merged_native_libs`, and the plugin then falls back to the Android Gradle Plugin's `native-debug-symbols.zip`, which depends on `debugSymbolLevel`.
+
+Native crash **reporting** is a separate matter from symbol upload: the NDK module detects the crash, the upload makes it readable. The package brings in the NDK module either way.
+
+## Release build checklist
+
+Before you ship, check each of these in `android/`:
+
+- [ ] `android/app/build.gradle` sets `react.hermesCommand` to the package's `hermesc-preserve-js` launcher, on one line.
+- [ ] `android/app/build.gradle` ends with `apply from: …/bugsee-sourcemaps.gradle`.
+- [ ] `android/settings.gradle` lists `mavenCentral()` in `pluginManagement.repositories`.
+- [ ] `android/build.gradle` declares `com.bugsee.android.gradle` at the version in `native-versions.json`, with `apply false`.
+- [ ] `android/app/build.gradle` applies `com.bugsee.android.gradle` and declares `bugsee-android-ndk` at `android.sdk` from `native-versions.json`.
+- [ ] `android/bugsee.properties` has your Android app token in `app_token` and `plugin.ndk.enabled=true`, or your CI writes it.
+- [ ] The variant has a `versionName` and a `versionCode`.
+- [ ] A Release build logs `bugsee: uploaded source map `, and runs `uploadBugseeReleaseNative` (and `uploadBugseeReleaseMapping` when R8 is on).
+
+Then trigger a test crash in the Release build and check the report's frames; see [Check that the uploads happened](/sdk/react_native/symbolication/overview#check-that-the-uploads-happened).
+
+## Turning uploads off
+
+- **Source maps**: `-PbugseeUploadSourcemaps=false`, `bugseeUploadSourcemaps=false` in `android/gradle.properties`, or `BUGSEE_UPLOAD_SOURCEMAPS=false`.
+- **Mapping, native symbols and build info**: native symbols follow `plugin.ndk.enabled`, but the Gradle plugin 4.0.8 has no switch for its mapping upload. The Expo config plugin's `uploadSymbols: false` turns all of the plugin's upload tasks off with this line in `android/app/build.gradle`, which a bare app can use too:
+
+ ```groovy title="android/app/build.gradle"
+ tasks.matching { it.name.startsWith('uploadBugsee') }.configureEach { enabled = false }
+ ```
+
+## Expo prebuild
+
+With the [config plugin](/sdk/react_native/expo), `expo prebuild` writes everything on this page: `mavenCentral()` in `settings.gradle`, the plugin declaration and its application, the `hermesCommand`, the `bugsee-sourcemaps.gradle` line, the NDK dependency, and `android/bugsee.properties` with your token and `plugin.ndk.enabled=true`. Its `uploadSourcemaps`, `uploadSymbols`, `nativeCrashReporting` and `gradlePluginVersion` options control them; see [Plugin options](/sdk/react_native/expo#plugin-options).
+
+The config plugin edits Groovy files only. While any Kotlin DSL file it would edit (`settings.gradle.kts`, `build.gradle.kts` or the app `build.gradle.kts`) exists, it refuses every prebuild, even after you have made its edits by hand. With Kotlin DSL files, remove `@bugsee/react-native` from `plugins` in `app.json` and make every edit by hand: the ones on this page, in Kotlin syntax, and the iOS ones on [Symbolication: iOS](/sdk/react_native/symbolication/ios), since removing the plugin drops those too. See [Limits](/sdk/react_native/expo#limits).
+
+A `hermesCommand` that an earlier prebuild wrote (the `.sh` launcher on every operating system) is recognized and replaced by the per-OS one. A `hermesCommand` of your own that already names `hermesc-preserve-js` is left as it is.
+
+## Troubleshooting
+
+**The bundle task fails with "compiled the bundle with Hermes, but hermesc did not run through the preserve wrapper".** `bugsee-sourcemaps.gradle` is applied, but `react.hermesCommand` does not point at the package's launcher, so the bundle would ship without a debug ID. Set `hermesCommand` as in [JavaScript source maps](#1-javascript-source-maps).
+
+**On macOS or Linux, the bundle task fails with "Permission denied" on `hermesc-preserve-js.sh`.** The scripts of 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) are published without the executable bit. Run `chmod +x node_modules/@bugsee/react-native/scripts/*.sh`, ideally from a `postinstall` script; see the caution in [JavaScript source maps](#1-javascript-source-maps).
+
+**On Windows, the bundle task fails with "would run hermesc through … a shell script".** Your `hermesCommand` names `hermesc-preserve-js.sh`, which earlier instructions gave for every OS. `cmd` cannot run it. Use the per-OS line above, which picks `hermesc-preserve-js.cmd` on Windows.
+
+**On Windows, with a project path that contains spaces or parentheses.** React Native runs `hermesCommand` through `cmd /c`, which cuts a path like `C:\Program Files (x86)\…`. On Windows the hook then gives the launcher to React Native relative to the project root, as React Native gives its own paths. A long project path can still pass Windows' 260-character limit in React Native's own native build, which is unrelated to Bugsee.
+
+**`bugsee: source map upload skipped: no app token is configured`** (or `the app token is the placeholder`). Put your Android app token in `app_token` in `android/bugsee.properties`, or export `BUGSEE_APP_TOKEN` for the build.
+
+**`bugsee: source map upload skipped: the app version or build number is unknown`.** The variant has no `versionName` or `versionCode`. Set both in `defaultConfig` or the flavor.
+
+**`bugsee: hermesFlags has no -output-source-map …`.** Your `react { hermesFlags }` leaves out `-output-source-map`. Add it back.
+
+**`bugsee: source map upload failed (@bugsee/cli is not installed)`.** The package's `@bugsee/cli` dependency, or its platform binary, is missing from `node_modules`. Its binary comes from an optional dependency; installs that skip optional dependencies, or a registry mirror that lacks `@bugsee/cli-`, leave it out. Under pnpm, see [pnpm](/sdk/react_native/installation#pnpm).
+
+**Gradle cannot find the plugin `com.bugsee.android.gradle`.** `pluginManagement.repositories` in `android/settings.gradle` lacks `mavenCentral()`.
+
+**Configuration fails with "Must apply 'com.android.application' or 'com.android.library' first!".** The plugin is applied to the root project. Declare it in `android/build.gradle` with `apply false`, and apply it in `android/app/build.gradle`.
+
+**Native frames show function names but no file and line.** The library was shipped stripped, such as `libhermesvm.so` from Maven; only its symbol table can be uploaded. Your own libraries keep their debug info in `merged_native_libs` and get file and line.
+
+**JavaScript frames stay minified though the upload succeeded.** Check that the report came from the same build: the debug ID in the build log identifies the bundle. A report from a debug build points at Metro's bundle, which is never uploaded.
+
+**Android reports have no `fetch` or XHR network events.** The Bugsee Gradle plugin is not applied to `android/app`. See [The Bugsee Gradle plugin](#2-the-bugsee-gradle-plugin).
+
+## Related pages
+
+- [Symbolication overview](/sdk/react_native/symbolication/overview): what each upload is for, tokens and verification.
+- [Symbolication: iOS](/sdk/react_native/symbolication/ios): the iOS side.
+- [Expo](/sdk/react_native/expo): the config plugin that writes these edits.
+- [Gradle plugin overview](/sdk/android/gradle-plugin): the Bugsee Gradle plugin in depth.
diff --git a/docs/sdk/react_native/symbolication/ios.mdx b/docs/sdk/react_native/symbolication/ios.mdx
new file mode 100644
index 0000000..c1ff711
--- /dev/null
+++ b/docs/sdk/react_native/symbolication/ios.mdx
@@ -0,0 +1,277 @@
+---
+title: "Symbolication: iOS"
+description: "Setting up a bare React Native 7.x iOS app to upload JavaScript source maps from the bundle phase and dSYMs from the Archive, including React Native's own dSYMs, and fixing what goes wrong."
+sidebar_position: 3
+slug: "/sdk/react_native/symbolication/ios"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+An iOS Release build needs two uploads for readable reports, made at two different stages of the build:
+
+| What | Where | Why there |
+| --- | --- | --- |
+| JavaScript source map | The **Bundle React Native code and images** build phase, pointed at the package's `bugsee-xcode.sh` | The bundle and its map exist only while the build runs. |
+| dSYMs (your code, Bugsee's, and optionally React Native's) | A Run Script in the scheme's **Archive** post-actions, running `bugsee-cli xcode post-action` | The Archive and its `dSYMs/` folder exist only after the Archive. |
+
+This page is for a bare app, where you own `ios/`. With Expo prebuild, the [config plugin](/sdk/react_native/expo) makes the same edits on each prebuild; see [Expo prebuild](#expo-prebuild). [Symbolication overview](/sdk/react_native/symbolication/overview) explains what each upload is for.
+
+The setup is the same whether the app gets the SDK through CocoaPods or through React Native's Swift Package Manager integration.
+
+## 1. The bundle phase: JavaScript source maps
+
+In Xcode, select the app target, open **Build Phases**, and find **Bundle React Native code and images**. It runs React Native's `react-native-xcode.sh`. Point it at the package's `bugsee-xcode.sh` instead:
+
+```sh title="Bundle React Native code and images"
+set -e
+
+WITH_ENVIRONMENT="$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh"
+REACT_NATIVE_XCODE="${SRCROOT}/../node_modules/@bugsee/react-native/scripts/bugsee-xcode.sh"
+
+/bin/sh -c "\"$WITH_ENVIRONMENT\" \"$REACT_NATIVE_XCODE\""
+```
+
+:::caution[7.0.0-beta1 and 7.0.0-beta2: scripts without the executable bit]
+In 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) the package's shell scripts are published without the executable bit (mode 644). `with-environment.sh` runs the script it is given directly, so the phase above fails with "Permission denied". Use one of these:
+
+- **Run the script through `/bin/bash`**, as the Expo config plugin's phase does. This phase reads `.xcode.env` and `.xcode.env.local` the same way, then runs `bugsee-xcode.sh` with `bash`, so it works with or without the executable bit:
+
+ ```sh title="Bundle React Native code and images"
+ set -e
+
+ WITH_ENVIRONMENT="$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh"
+ REACT_NATIVE_XCODE="${SRCROOT}/../node_modules/@bugsee/react-native/scripts/bugsee-xcode.sh"
+
+ /bin/bash -c 'hook="$1"; set --; . "$0"; exec /bin/bash "$hook"' "$WITH_ENVIRONMENT" "$REACT_NATIVE_XCODE"
+ ```
+
+- **Make the scripts executable after every install**, for example with `"postinstall": "chmod +x node_modules/@bugsee/react-native/scripts/*.sh"` in your app's `package.json`, and keep the phase above. A CI job that installs with `--ignore-scripts` needs the same `chmod` as its own step.
+:::
+
+The path in `REACT_NATIVE_XCODE` assumes the package is installed in the app's own `node_modules`, next to `ios/`. In a monorepo or another hoisted layout, point it at where `@bugsee/react-native` really is (for example `${SRCROOT}/../../../node_modules/…`). To check, run `node --print "require.resolve('@bugsee/react-native/package.json')"` from the app's root.
+
+`bugsee-xcode.sh` runs React Native's own `react-native-xcode.sh`, so the bundle is built exactly as before. It then composes the Hermes source map, gives the bundle and the map a debug ID (compiling the stamped JavaScript to bytecode again, so the ID is in what ships), and uploads the map with `@bugsee/cli`.
+
+Give the upload your iOS app token in the build environment. React Native's `with-environment.sh` reads `ios/.xcode.env` and then `ios/.xcode.env.local`, so a line there reaches the phase:
+
+```sh title="ios/.xcode.env.local"
+export BUGSEE_APP_TOKEN=
+```
+
+`BUGSEE_TOKEN_IOS` works too. React Native's template keeps `.xcode.env.local` out of version control, which suits a token; your CI can write the file, or export the variable for `xcodebuild`.
+
+### Upload settings
+
+- **Release only.** A configuration whose name contains `Debug` skips the upload, unless `BUGSEE_UPLOAD_DEBUG_SOURCEMAPS=true`. A Debug build for the Simulator does not bundle at all, as React Native leaves that to Metro.
+- **Version and build number.** Xcode's `MARKETING_VERSION` and `CURRENT_PROJECT_VERSION`. Without them the upload is skipped.
+- **Endpoint.** `BUGSEE_ENDPOINT`, for a self-hosted, staging or regional Bugsee. Unset, the map goes to Bugsee's production API.
+- **Turning it off.** `BUGSEE_UPLOAD_SOURCEMAPS=false` in the build environment. The debug ID is still injected.
+- **Failures.** Without a token the phase bundles as usual and logs that it skipped the upload. A failed upload logs a warning and the build continues: the CLI's own `error:` lines are relayed as `warning: bugsee: …`, so Xcode does not read them as build errors.
+
+## 2. The Archive post-action: dSYMs
+
+Native frames, yours and Bugsee's, resolve through the dSYMs of the Archive. A scheme post-action uploads them after each Archive:
+
+1. Open **Product > Scheme > Edit Scheme**, and select **Archive**.
+2. Expand it, select **Post-actions**, click **+** and choose **New Run Script Action**.
+3. Set **Provide build settings from** to your app target. Without it the script gets none of the build settings it reads, such as `PROJECT_DIR`.
+4. Paste the script below.
+5. Make sure the scheme is **Shared** (the checkbox in **Manage Schemes**), so it lives in `xcshareddata/` and your team and CI get it too.
+
+This is the script the Expo config plugin writes. It finds the token, stops without a real one, finds `node` and the package's `@bugsee/cli`, and runs `bugsee-cli xcode post-action`:
+
+{/* cspell:disable */}
+
+```sh title="Archive post-action: Upload dSYMs"
+CREDS="${PROJECT_DIR}/../credentials.json"
+TOKEN="$BUGSEE_APP_TOKEN"
+if [ -z "$TOKEN" ]; then
+ TOKEN="$BUGSEE_TOKEN_IOS"
+fi
+if [ -z "$TOKEN" ] && [ -f "$CREDS" ]; then
+ TOKEN=$(/usr/bin/plutil -extract ios raw -o - "$CREDS" 2>/dev/null || true)
+fi
+TOKEN_CHECK=$(printf '%s' "$TOKEN" | /usr/bin/tr -d ' \t\r\n-')
+if [ -z "$TOKEN_CHECK" ]; then
+ echo "warning: bugsee: dSYM upload skipped: no app token is configured"
+ exit 0
+fi
+case "$TOKEN_CHECK" in
+ 000000000000[0123456789abcdefABCDEF]000[0123456789abcdefABCDEF]000000000000000)
+ echo "warning: bugsee: dSYM upload skipped: the app token is the placeholder"
+ exit 0
+ ;;
+esac
+# An "error:" line reads as a build error to Xcode; a failed upload is a warning.
+run_cli() {
+ CLI_OUT=$("$@" 2>&1)
+ CLI_RC=$?
+ if [ -n "$CLI_OUT" ]; then
+ printf '%s\n' "$CLI_OUT" | /usr/bin/sed -E 's/^(.*: )?([Ff]atal [Ee]rror|[Ee]rror): (.*)$/warning: bugsee: \3/'
+ fi
+ return $CLI_RC
+}
+if [ -n "$TOKEN" ]; then
+ export BUGSEE_APP_TOKEN="$TOKEN"
+fi
+if [ -z "$BUGSEE_ENDPOINT" ] && [ -f "$CREDS" ]; then
+ ENDPOINT=$(/usr/bin/plutil -extract endpoint raw -o - "$CREDS" 2>/dev/null || true)
+ if [ -n "$ENDPOINT" ]; then
+ export BUGSEE_ENDPOINT="$ENDPOINT"
+ fi
+fi
+
+# Archive's PATH has no node, and the npm shim's shebang searches PATH.
+if [ ! -x "$NODE_BINARY" ]; then
+ if [ -f "${PROJECT_DIR}/.xcode.env" ]; then
+ . "${PROJECT_DIR}/.xcode.env"
+ fi
+ if [ -f "${PROJECT_DIR}/.xcode.env.local" ]; then
+ . "${PROJECT_DIR}/.xcode.env.local"
+ fi
+fi
+if [ ! -x "$NODE_BINARY" ]; then
+ RN_FIND=""
+ if [ -n "$REACT_NATIVE_PATH" ] && [ -f "$REACT_NATIVE_PATH/scripts/find-node-for-xcode.sh" ]; then
+ RN_FIND="$REACT_NATIVE_PATH/scripts/find-node-for-xcode.sh"
+ elif [ -f "${PROJECT_DIR}/../node_modules/react-native/scripts/find-node-for-xcode.sh" ]; then
+ RN_FIND="${PROJECT_DIR}/../node_modules/react-native/scripts/find-node-for-xcode.sh"
+ fi
+ if [ -n "$RN_FIND" ]; then
+ NODE_BINARY=$(/bin/bash -c '. "$1" >/dev/null 2>&1; command -v node' _ "$RN_FIND" || true)
+ fi
+fi
+if [ -n "$NODE_BINARY" ] && [ -x "$NODE_BINARY" ]; then
+ PATH="$(dirname "$NODE_BINARY"):$PATH"
+ export PATH NODE_BINARY
+ APP_ROOT="${PROJECT_DIR}/.."
+ if [ "$(uname -m)" = "x86_64" ]; then
+ NATIVE_PKG="$("$NODE_BINARY" --print "try { const path = require('path'); const appRoot = process.argv[1]; const wrapperPkg = require.resolve('@bugsee/react-native/package.json', { paths: [appRoot] }); const wrapperDir = path.dirname(wrapperPkg); const cliPkg = require.resolve('@bugsee/cli/package.json', { paths: [wrapperDir] }); const cliDir = path.dirname(cliPkg); require.resolve('@bugsee/cli-darwin-x64/package.json', { paths: [cliDir] }); } catch (e) { '' }" "$APP_ROOT")"
+ else
+ NATIVE_PKG="$("$NODE_BINARY" --print "try { const path = require('path'); const appRoot = process.argv[1]; const wrapperPkg = require.resolve('@bugsee/react-native/package.json', { paths: [appRoot] }); const wrapperDir = path.dirname(wrapperPkg); const cliPkg = require.resolve('@bugsee/cli/package.json', { paths: [wrapperDir] }); const cliDir = path.dirname(cliPkg); require.resolve('@bugsee/cli-darwin-arm64/package.json', { paths: [cliDir] }); } catch (e) { '' }" "$APP_ROOT")"
+ fi
+ if [ -n "$NATIVE_PKG" ]; then
+ NATIVE_BIN="$(dirname "$NATIVE_PKG")/bin/bugsee-cli"
+ if [ -x "$NATIVE_BIN" ]; then
+ run_cli "$NATIVE_BIN" xcode post-action
+ exit $?
+ fi
+ fi
+ CLI_JS="$("$NODE_BINARY" --print "try { const fs = require('fs'); const path = require('path'); const appRoot = process.argv[1]; const wrapperPkg = require.resolve('@bugsee/react-native/package.json', { paths: [appRoot] }); const wrapperDir = path.dirname(wrapperPkg); const cliPkg = require.resolve('@bugsee/cli/package.json', { paths: [wrapperDir] }); const cliDir = path.dirname(cliPkg); const rel = JSON.parse(fs.readFileSync(cliPkg, 'utf8')).bin['bugsee-cli']; rel ? path.join(cliDir, rel) : ''; } catch (e) { '' }" "$APP_ROOT")"
+ if [ -n "$CLI_JS" ]; then
+ run_cli "$NODE_BINARY" "$CLI_JS" xcode post-action
+ exit $?
+ fi
+fi
+
+echo "bugsee-cli: not found" >&2
+exit 1
+```
+
+{/* cspell:enable */}
+
+Keep its token check. Without a real token the script has to stop, exit 0, before it runs `bugsee-cli`, which would otherwise register the build and send the placeholder token to your endpoint, or to production when none is set.
+
+### Give the post-action a token
+
+The post-action reads its token from `BUGSEE_APP_TOKEN`, then `BUGSEE_TOKEN_IOS`, in the environment the Archive runs in. It does **not** read the token from `ios/.xcode.env.local`: it reads `.xcode.env` and `.xcode.env.local` only later, and only to find `node`.
+
+- **Archives from the command line or CI** (`xcodebuild archive`): export `BUGSEE_APP_TOKEN` in the shell that runs `xcodebuild`.
+- **Archives from the Xcode GUI**, which does not inherit a shell environment: write the token into the script, as the Expo config plugin does. Replace the line `TOKEN="$BUGSEE_APP_TOKEN"` with:
+
+ ```sh
+ TOKEN=''
+ if [ -z "$TOKEN" ]; then
+ TOKEN="$BUGSEE_APP_TOKEN"
+ fi
+ ```
+
+ The token is then in the scheme file, so keep that in mind before you commit it.
+
+For a custom endpoint, export `BUGSEE_ENDPOINT` the same way (or add an `export BUGSEE_ENDPOINT='…'` line at the top of the script).
+
+### What `xcode post-action` does
+
+`bugsee-cli xcode post-action` registers the build with Bugsee and uploads the Archive's dSYMs. By default it runs only on **Archive** of a **Release** configuration, and it detaches into the background, so it never holds up or fails the Archive; its log goes to `$PROJECT_TEMP_DIR/bugsee-cli.log`. Its gating, the build information it collects, and the environment variables that tune it are on [iOS build publishing](/cli/xcode).
+
+Release configurations generate dSYMs by default. If you changed it, set **Debug Information Format** back to **DWARF with dSYM File** for Release.
+
+## 3. React Native's own dSYMs
+
+React Native's prebuilt `React.xcframework` ships without dSYMs. After an Archive, the `React` frames in a crash stay raw addresses (`React 0x10271dbc4`) while your own frames and Bugsee's symbolicate. **Leaving this off means React Native frames on iOS show as raw addresses.**
+
+React Native downloads its dSYMs only when `pod install` runs with `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1`:
+
+```sh
+cd ios && RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1 pod install
+```
+
+With it set, the Archive's `dSYMs/` folder includes React's dSYMs, and the post-action uploads them with the rest. Export it wherever you run `pod install`, CI included.
+
+The dSYMs are fetched together with the prebuilt `React-Core-prebuilt` pod, so the variable does nothing for a pod already in `ios/Pods`, or in the CocoaPods cache, from an earlier `pod install` without it: the log then shows no `Resolved stable dSYMs`, and the Archive has no `React.framework.dSYM`. On such a machine, remove the pod and install again, from the app's root directory:
+
+```sh
+rm -rf ios/Pods/React-Core-prebuilt
+pod cache clean React-Core-prebuilt --all
+(cd ios && RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1 pod install)
+```
+
+A fresh CI checkout is not affected. To check that it worked, look for `dSYMs/React.framework.dSYM` in the Archive.
+
+The trade-off: `pod install` makes an extra download. React Native fetches the dSYMs in the same step as the prebuilt framework, so a failed download drops the prebuilt React for that install, and a failure while unpacking aborts `pod install`. Apps that build React Native from source already have its dSYMs.
+
+## Release build checklist
+
+- [ ] The **Bundle React Native code and images** phase runs `@bugsee/react-native/scripts/bugsee-xcode.sh` through `with-environment.sh`.
+- [ ] `ios/.xcode.env.local` (or your CI) exports `BUGSEE_APP_TOKEN` with your iOS app token.
+- [ ] The target has a `MARKETING_VERSION` and a `CURRENT_PROJECT_VERSION`.
+- [ ] The shared scheme's **Archive** has the post-action, with **Provide build settings from** set to the app target.
+- [ ] The post-action gets a token: from the environment for command-line Archives, written into the script for Xcode GUI Archives.
+- [ ] If you want React Native's frames: `pod install` runs with `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1`, and the Archive contains `dSYMs/React.framework.dSYM`.
+- [ ] The Archive's build log shows `bugsee: uploaded source map `, and `$PROJECT_TEMP_DIR/bugsee-cli.log` shows the dSYM upload.
+
+Then trigger a test crash on a device and check the report's frames; see [Check that the uploads happened](/sdk/react_native/symbolication/overview#check-that-the-uploads-happened).
+
+## iOS Simulator
+
+A crash on the iOS Simulator produces no report in this beta, so there is nothing to symbolicate. Test crash reporting, and symbolication with it, on a physical device. See [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting#native-crashes).
+
+## Turning uploads off
+
+- **Source maps**: `BUGSEE_UPLOAD_SOURCEMAPS=false` in the build environment, for example in `ios/.xcode.env.local`. The bundle still gets its debug ID.
+- **dSYMs and build info**: remove the Archive post-action from the scheme, or set `BUGSEE_BUILD_INFO_ENABLED=0` in the environment the Archive runs in, which makes `bugsee-cli xcode post-action` do nothing; see [Gating](/cli/xcode#gating). The Expo config plugin's `uploadSymbols: false` removes the post-action.
+
+## Expo prebuild
+
+With the [config plugin](/sdk/react_native/expo), `expo prebuild` makes all of these edits: it swaps the bundle phase's call to `react-native-xcode.sh` for `bugsee-xcode.sh`, inserts the dSYM post-action into every shared scheme under `ios/`, and writes your `appToken` into both, so an Archive from the Xcode GUI has it. React Native's dSYMs are opt-in, with `symbolicateReactNativeFrameworks: true`, which adds `ENV['RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS'] ||= '1'` to the top of `ios/Podfile`. See [What the plugin changes](/sdk/react_native/expo#what-the-plugin-changes) and [React Native dSYMs on iOS](/sdk/react_native/expo#react-native-dsyms-on-ios).
+
+## Troubleshooting
+
+**The bundle phase fails with "Permission denied" on `bugsee-xcode.sh`.** The scripts of 7.0.0-beta1 and 7.0.0-beta2 (fixed in 7.0.0-beta3) are published without the executable bit. Run the script through `/bin/bash`, or `chmod +x` the package's scripts after each install; see the caution in [The bundle phase](#1-the-bundle-phase-javascript-source-maps).
+
+**`bugsee: source map upload skipped: no app token is configured`** (or `the app token is the placeholder`). The bundle phase has no real token. Export `BUGSEE_APP_TOKEN` in `ios/.xcode.env.local`; a plain assignment without `export` does not reach the script.
+
+**`bugsee: source map upload skipped: Debug configuration …`.** Expected for Debug builds. Archive a Release configuration, or set `BUGSEE_UPLOAD_DEBUG_SOURCEMAPS=true` if you really want Debug maps.
+
+**`bugsee: source map upload skipped: the app version or build number is unknown`.** Set **Version** (`MARKETING_VERSION`) and **Build** (`CURRENT_PROJECT_VERSION`) on the target.
+
+**The bundle phase fails with "hermesc not found; the debug-id stub would not be in the bytecode".** The script could not find the Hermes compiler. It looks at `HERMES_CLI_PATH`, then `Pods/hermes-engine/destroot/bin/hermesc`, then React Native's `hermes-compiler` package. Run `pod install` again, or set `HERMES_CLI_PATH`.
+
+**`warning: bugsee: dSYM upload skipped: no app token is configured` after an Archive.** The post-action has no token in its environment. A token in `ios/.xcode.env.local` does not reach it; see [Give the post-action a token](#give-the-post-action-a-token).
+
+**The post-action prints `bugsee-cli: not found`.** It found no `node`, or no `@bugsee/cli` next to `@bugsee/react-native`. Check `NODE_BINARY` in `ios/.xcode.env`, and that `@bugsee/cli` and its platform package (`@bugsee/cli-darwin-arm64` or `@bugsee/cli-darwin-x64`) are installed. Installs that skip optional dependencies leave the platform package out; under pnpm, see [pnpm](/sdk/react_native/installation#pnpm).
+
+**No dSYMs were uploaded, and the post-action printed nothing.** It runs in the background: read `$PROJECT_TEMP_DIR/bugsee-cli.log`. Check that **Provide build settings from** names the app target, and that you archived a Release configuration.
+
+**`React` frames stay raw addresses.** See [React Native's own dSYMs](#3-react-natives-own-dsyms), including the stale `React-Core-prebuilt` pod.
+
+**JavaScript frames stay minified though the upload succeeded.** Check that the report came from the same build: the debug ID in the build log identifies the bundle. A report from a Debug build that loaded its JavaScript from Metro points at Metro's bundle, which is never uploaded.
+
+## Related pages
+
+- [Symbolication overview](/sdk/react_native/symbolication/overview): what each upload is for, tokens and verification.
+- [Symbolication: Android](/sdk/react_native/symbolication/android): the Android side.
+- [iOS crash symbolication](/sdk/ios/symbolication): dSYMs for the native iOS SDK, including manual upload from the dashboard.
+- [iOS build publishing](/cli/xcode): the `xcode post-action` command in depth.
diff --git a/docs/sdk/react_native/symbolication/overview.mdx b/docs/sdk/react_native/symbolication/overview.mdx
new file mode 100644
index 0000000..acedc35
--- /dev/null
+++ b/docs/sdk/react_native/symbolication/overview.mdx
@@ -0,0 +1,109 @@
+---
+title: "Symbolication overview"
+description: "What Bugsee needs to turn React Native 7.x Release crash frames back into source, which build step uploads each piece, and how to check that the uploads happened."
+sidebar_position: 1
+slug: "/sdk/react_native/symbolication/overview"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+A Release build ships minified JavaScript compiled to Hermes bytecode, Java and Kotlin code renamed by R8, and stripped native libraries. A crash from that build carries addresses and minified names. To show you your own file names, functions and lines, Bugsee needs the matching debug files for that exact build, uploaded while the build runs.
+
+A React Native app has up to three kinds of frames in one report, and each kind has its own debug file and its own build step. This page explains the pieces. [Symbolication: Android](/sdk/react_native/symbolication/android) and [Symbolication: iOS](/sdk/react_native/symbolication/ios) have the setup for a bare app. An Expo app gets all of it from the [config plugin](/sdk/react_native/expo).
+
+## What gets symbolicated
+
+| Frames | Platform | Debug file | Uploaded by |
+| --- | --- | --- | --- |
+| JavaScript | Android | Composed Hermes source map, with a debug ID | The package's Gradle hook (`scripts/bugsee-sourcemaps.gradle`) and Hermes wrapper (`react.hermesCommand`) |
+| JavaScript | iOS | Composed Hermes source map, with a debug ID | The package's `scripts/bugsee-xcode.sh`, run by the **Bundle React Native code and images** build phase |
+| Java and Kotlin | Android | R8/ProGuard `mapping.txt` | The Bugsee Gradle plugin (`uploadBugseeMapping`) |
+| Native (C/C++) | Android | Native debug symbols of every `.so` | The Bugsee Gradle plugin (`uploadBugseeNative`, with `plugin.ndk.enabled=true`) |
+| Native (Objective-C, Swift, C++) | iOS | dSYMs from the Archive | A scheme **Archive** post-action that runs `bugsee-cli xcode post-action` |
+| React Native's own frameworks | iOS | React Native's dSYMs | The same post-action, once `pod install` ran with `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1` |
+
+Without these uploads the app still builds and runs, and reports still arrive. Only the frames stay unreadable: JavaScript frames point into the bundle, and native frames are raw addresses.
+
+## How JavaScript frames are matched: debug IDs
+
+JavaScript symbolication in 7.x does not depend on file names or on the app version. It uses a **debug ID**, a UUID derived from the bundle's content:
+
+1. After React Native composes the final source map, the build hook runs `bugsee-cli sourcemaps inject`. It writes the debug ID into the JavaScript bundle and into the composed map, together with a small runtime stub that registers the ID in `globalThis._bugseeDebugIds`.
+2. With Hermes, the hook then compiles the stamped JavaScript to bytecode again, so the stub is in the bytecode that ships, and copies the ID back onto the recomposed map.
+3. The hook uploads the composed map with `bugsee-cli debug-files upload --type sourcemaps`, under the build's version and build number.
+4. At runtime, when the SDK reports a JavaScript error or crash, it reads the registered IDs and sends them with the exception, per frame. The server picks the map with the matching ID.
+
+Because the ID comes from the bundle's content, a rebuilt but unchanged bundle has the same ID, and a map the server already has is not uploaded twice. See [Source maps](/cli/sourcemaps) in the Bugsee CLI documentation for how the CLI injects and uploads.
+
+Two details matter for Hermes, and are why you should use the package's hooks instead of running the CLI yourself:
+
+- The ID has to go on the **composed** map, the one written after `compose-source-maps.js`. The intermediate compiler map is never consulted, and composing again drops the ID.
+- The stub has to be in the JavaScript that `hermesc` compiles. On Android, that is what the Hermes wrapper in `react.hermesCommand` is for: it keeps the JavaScript aside before `hermesc` runs, so the hook can stamp it and compile it again.
+
+Before upload, the hooks rewrite absolute paths in the map's `sources` to paths relative to the project root (`/src/App.tsx`, or `../packages/ui/Button.tsx` for a workspace package outside the root), so the dashboard does not show your build machine's directory layout. The map on disk is not changed. The map is uploaded with its `sourcesContent`, so your source code goes with it; the hooks have no switch to strip it in this beta.
+
+## The pieces and who does what
+
+| Piece | What it is | What it does here |
+| --- | --- | --- |
+| `@bugsee/cli` | The Bugsee CLI, a dependency of `@bugsee/react-native` (pinned exactly, 0.7.12 in `7.0.0-beta3`). Its binary comes from a platform-specific optional dependency. | Stamps and uploads source maps for the package's build hooks, and uploads dSYMs from the iOS post-action. See [Bugsee CLI](/cli). |
+| Package build hooks | `scripts/bugsee-sourcemaps.gradle` and `scripts/hermesc-preserve-js.*` (Android), `scripts/bugsee-xcode.sh` (iOS), shipped in the package. | Give each Release bundle a debug ID and upload its source map. They do not need the Bugsee Gradle plugin. |
+| Bugsee Gradle plugin | `com.bugsee.android.gradle`, version 4.0.8 for `7.0.0-beta3`. A Gradle plugin, so autolinking cannot add it. | Uploads the R8 mapping, the native symbols and the build info of each Release build, with its own copy of the CLI. It also instruments OkHttp, which is how `fetch` and `XMLHttpRequest` reach Bugsee's network capture on Android; see [Installation](/sdk/react_native/installation#android). |
+| iOS bundle phase | Xcode's **Bundle React Native code and images** phase, pointed at `bugsee-xcode.sh` instead of React Native's `react-native-xcode.sh`. | Runs React Native's script, then stamps and uploads the source map. |
+| iOS Archive post-action | A Run Script in the scheme's **Archive** post-actions that runs `bugsee-cli xcode post-action`. | Registers the build and uploads its dSYMs, React Native's included when they are in the Archive. See [iOS build publishing](/cli/xcode). |
+| Expo config plugin | `@bugsee/react-native` in the `plugins` of `app.json`. | Writes all of the above on `expo prebuild`. React Native's dSYMs are opt-in, with `symbolicateReactNativeFrameworks`. See [Expo](/sdk/react_native/expo#what-the-plugin-changes). |
+
+The Bugsee Gradle plugin and the Archive post-action also register the build itself with Bugsee (build info). The [Gradle plugin documentation](/sdk/android/gradle-plugin/builds-upload) and [iOS build publishing](/cli/xcode) describe that part.
+
+## What to set up
+
+| You use | Do this |
+| --- | --- |
+| Expo prebuild | Add the [config plugin](/sdk/react_native/expo) with your `appToken` and run `npx expo prebuild`. Add `symbolicateReactNativeFrameworks: true` if you want React Native's own frames on iOS. |
+| Expo with a Kotlin DSL Gradle file | The config plugin refuses every prebuild while any of `settings.gradle.kts`, `build.gradle.kts` or the app `build.gradle.kts` exists, even after you make its edits by hand. Remove `@bugsee/react-native` from `plugins`, which also drops its iOS edits, and make every edit by hand, as in [Symbolication: Android](/sdk/react_native/symbolication/android) and [Symbolication: iOS](/sdk/react_native/symbolication/ios). |
+| A bare app, Android | Add the source-map hooks, the Bugsee Gradle plugin and `android/bugsee.properties`: [Symbolication: Android](/sdk/react_native/symbolication/android). |
+| A bare app, iOS | Point the bundle phase at `bugsee-xcode.sh`, give it a token, add the Archive post-action, and optionally React Native's dSYMs: [Symbolication: iOS](/sdk/react_native/symbolication/ios). |
+| CI | Export `BUGSEE_APP_TOKEN` in the job, per platform; see [Tokens and endpoints](#tokens-and-endpoints). On iOS, also export `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1` where the job runs `pod install`, if you want React Native's dSYMs. |
+| Builds that must not upload | Expo: `uploadSourcemaps: false` and `uploadSymbols: false`. Bare app: `-PbugseeUploadSourcemaps=false` or `BUGSEE_UPLOAD_SOURCEMAPS=false` for source maps; on Android, disable the Gradle plugin's `uploadBugsee*` tasks as in [Turning uploads off](/sdk/react_native/symbolication/android#turning-uploads-off); leave out the post-action on iOS. A missing or placeholder token skips the source-map upload and the iOS post-action. The Bugsee Gradle plugin skips only when no token is set; with Expo, the config plugin leaves the placeholder out of `android/bugsee.properties`. |
+
+## When uploads run
+
+- **Release only.** On Android, React Native bundles only non-debuggable variants (a debug build loads its JavaScript from Metro), so the source-map hook runs for Release builds. On iOS the bundle phase skips the upload in a configuration whose name contains `Debug`, unless `BUGSEE_UPLOAD_DEBUG_SOURCEMAPS=true`. The dSYM post-action runs on **Archive** of a Release configuration (the CLI's default gating; see [Gating](/cli/xcode#gating)).
+- **A real token is required.** No token, or the placeholder token `00000000-0000-4000-8000-000000000000`, skips the source-map upload and the dSYM post-action with one line in the build log, and the build carries on.
+- **A failed upload never fails the build.** The source-map hooks print a warning and continue. The dSYM post-action runs in the background by default, so it does not hold up or fail the Archive.
+
+## Tokens and endpoints
+
+The uploads use the same **Bugsee app token** your app passes to `Bugsee.launch`. Tokens are per platform: upload Android files with your Android app's token and iOS files with your iOS app's token. You find the token in the Bugsee dashboard, in your application's settings.
+
+| Upload | Where the token comes from |
+| --- | --- |
+| Android source map | `app_token` in `android/bugsee.properties`, then the `BUGSEE_APP_TOKEN` environment variable, then `BUGSEE_TOKEN_ANDROID` |
+| Android mapping and native symbols | The Bugsee Gradle plugin's token: `app_token` in `android/bugsee.properties`, or the plugin's `appToken` setting; see [Gradle plugin configuration](/sdk/android/gradle-plugin/configuration) |
+| iOS source map | The token the Expo plugin wrote into the bundle phase, then `BUGSEE_APP_TOKEN`, then `BUGSEE_TOKEN_IOS`, from the build environment (for example `ios/.xcode.env.local`) |
+| iOS dSYMs | The token the Expo plugin wrote into the post-action, then `BUGSEE_APP_TOKEN`, then `BUGSEE_TOKEN_IOS`, from the environment the Archive runs in. The post-action does not read `ios/.xcode.env.local` for its token; see [Symbolication: iOS](/sdk/react_native/symbolication/ios). |
+
+Everything uploads to Bugsee's production API unless you set an endpoint. For a self-hosted, staging or regional Bugsee, set the API base: `plugin.endpoint` in `android/bugsee.properties` (read by the Gradle plugin and the Android source-map hook) or `BUGSEE_ENDPOINT` in the environment (read by the source-map hooks and the CLI). The Expo plugin's `endpoint` option writes all of these, and the runtime endpoint too; see [Custom endpoint](/sdk/react_native/expo#custom-endpoint).
+
+:::note[Tokens in committed files]
+`android/bugsee.properties`, an `ios/.xcode.env.local`, and with Expo the `ios/` project and shared scheme, all hold the token in plain text. Keep `android/bugsee.properties` and `ios/.xcode.env.local` out of version control if the token is private, and inject it from your CI secrets instead.
+:::
+
+## Check that the uploads happened
+
+Build a Release build (an Archive, on iOS) and read the build log:
+
+- **Source maps**: a line `bugsee: uploaded source map ` from the bundle task (Android: `createBundleJsAndAssets`; iOS: the **Bundle React Native code and images** phase). A skipped upload says why, for example `bugsee: source map upload skipped: no app token is configured`, and a failed one `bugsee: source map upload failed (…); the app build continues`.
+- **Android mapping and native symbols**: the `uploadBugseeMapping` and `uploadBugseeNative` tasks run after `assemble` or `bundle`.
+- **iOS dSYMs**: the post-action runs in the background and writes its log to `$PROJECT_TEMP_DIR/bugsee-cli.log`; see [Background vs. foreground](/cli/xcode#background-vs-foreground). A skipped post-action prints `warning: bugsee: dSYM upload skipped: …`.
+
+Then check the result end to end: in a Release build, trigger a test crash with `Bugsee.testJsCrash()` or `Bugsee.testNativeCrash()` (see [Crash & error reporting](/sdk/react_native/manual/crash-error-reporting)), relaunch the app so the report uploads, and open it in the dashboard. JavaScript frames should name your source files, and native frames your functions. Use a real device for iOS: the iOS Simulator has no crash reporting.
+
+## Related pages
+
+- [Symbolication: Android](/sdk/react_native/symbolication/android): source-map hooks, the Bugsee Gradle plugin and native symbols.
+- [Symbolication: iOS](/sdk/react_native/symbolication/ios): the bundle phase, the dSYM post-action and React Native's dSYMs.
+- [Expo](/sdk/react_native/expo): the config plugin that wires all of this on prebuild.
+- [Bugsee CLI](/cli): the tool behind every upload.
diff --git a/docs/sdk/react_native/user-session-data.mdx b/docs/sdk/react_native/user-session-data.mdx
new file mode 100644
index 0000000..b6f1072
--- /dev/null
+++ b/docs/sdk/react_native/user-session-data.mdx
@@ -0,0 +1,147 @@
+---
+title: "User & session data"
+description: "Attach a user identifier and custom attributes to every report with Bugsee React Native SDK 7.x: accepted values, platform limits, reading them back, and errors."
+sidebar_position: 11
+slug: "/sdk/react_native/user-session-data"
+---
+
+:::warning[Beta]
+This page documents Bugsee React Native SDK **7.x**, which is in beta and can change between betas. The stable release is **6.x**: see the [6.x documentation](/sdk/react_native/v6/installation). Upgrading? See [Migrating from 6.x to 7.x](/sdk/react_native/migration).
+:::
+
+Annotate every report with facts about the current user and session: a **user identifier**, which says who the user is, and custom key/value **attributes**, for anything else (plan, region, feature flags). Both go with every report the SDK sends.
+
+## User identity
+
+The user identifier is a stable string, such as your backend user ID, that ties a user's reports together in the Bugsee dashboard. Use attributes for other facts about the user; use the identifier for **who** they are.
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+// Once the user has signed in
+Bugsee.setUserIdentifier('user-8f3a2c');
+
+// Read it back: undefined when none is set
+async function logCurrentUser() {
+ const id = await Bugsee.getUserIdentifier();
+ console.log('Bugsee user:', id ?? 'none');
+}
+
+// On sign-out: attributes persist across launches, so clear them too
+async function onSignOut(): Promise {
+ Bugsee.clearUserIdentifier();
+ await Bugsee.clearAllAttributes();
+}
+```
+
+| Method | Returns | Notes |
+| --- | --- | --- |
+| `setUserIdentifier(identifier)` | `void` | Synchronous. `identifier` must be a string, or it throws `TypeError`. An empty string clears the identifier, on both platforms. |
+| `getUserIdentifier()` | `Promise` | `undefined` when no identifier is set. |
+| `clearUserIdentifier()` | `void` | Synchronous. |
+
+No size limit applies to the identifier, so `setUserIdentifier` does not check one and does not return a promise.
+
+## Attributes
+
+Attributes are key/value pairs attached to every report. They **persist across launches** until you clear them, so set them when the fact changes (at sign-in, when the plan changes) rather than at every launch.
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function describeSession(): Promise {
+ await Bugsee.setAttribute('plan', 'pro');
+ await Bugsee.setAttribute('seats', 5);
+ await Bugsee.setAttribute('beta', true);
+}
+```
+
+| Method | Resolves to | Notes |
+| --- | --- | --- |
+| `setAttribute(name, value)` | `void` | Sets one attribute. Rejects when the value is invalid or the native SDK did not keep it. |
+| `getAttribute(name)` | `AttributeReadValue \| undefined` | One attribute's value, or `undefined` when it is not set. |
+| `getAllAttributes()` | `Record` | Every attribute currently set, as reports will carry them. |
+| `clearAttribute(name)` | `void` | Removes one attribute. Does nothing if it was not set. |
+| `clearAllAttributes()` | `void` | Removes every attribute. |
+
+Every attribute method returns a promise, including for an invalid argument: validation errors reject the promise rather than throwing synchronously. Await the calls, or add a `.catch`, so a rejection does not go unhandled.
+
+### Accepted values
+
+`name` must be a non-empty string. `value` (an `AttributeValue`) is one of:
+
+| Type | Rules |
+| --- | --- |
+| `string` | At most 1024 UTF-16 code units. See the iOS limit below. |
+| `number` | Finite (no `NaN` or `Infinity`), and smaller than 263 in magnitude. |
+| `boolean` | |
+
+Nothing else is accepted: no `null`, objects, arrays or dates. To remove an attribute, use `clearAttribute`.
+
+### Platform limits
+
+The platforms store values differently, and `setAttribute` reports whether the value was kept:
+
+- **iOS** drops a value whose stored (archived) size is over about 1.1 KB. A string of up to about 800 ASCII characters is safe on both platforms. A longer one, still within the 1024-unit limit above, can be kept on Android and rejected with `E_ATTRIBUTE_REJECTED` on iOS.
+- **Android** stores a whole number up to 253 − 1 in magnitude exactly, but stores a fractional number, or a larger whole number, as a 32-bit float. `setAttribute('ratio', 0.1)` then reads back as `0.10000000149011612`, which is the value the report carries.
+
+If a value was not kept, for a size limit or any other reason, the promise from `setAttribute` rejects with `E_ATTRIBUTE_REJECTED`, so a dropped value does not go unnoticed.
+
+### Reading attributes back
+
+```ts
+import Bugsee from '@bugsee/react-native';
+
+async function logAttributes(): Promise {
+ const plan = await Bugsee.getAttribute('plan'); // 'pro', or undefined
+ const all = await Bugsee.getAllAttributes(); // { plan: 'pro', seats: 5, beta: true }
+ console.log(plan, all);
+}
+```
+
+A read returns an `AttributeReadValue`: a string, number or boolean, or a `string[]` for a list (on Android, a set) of strings that native code stored directly (`setAttribute` cannot create one). Both `getAttribute` and `getAllAttributes` read the copy reports are built from, so they agree with each other and with the report.
+
+## Before launch
+
+What happens to an identifier or attribute set before `Bugsee.launch` is not specified in this beta: these calls are not held until launch. `setAttribute` still checks that the value was kept, so if it was not, the promise rejects with `E_ATTRIBUTE_REJECTED`; `setUserIdentifier` has no such check. Set the identifier and attributes after the promise from `launch` resolves.
+
+## Errors
+
+A failed attribute call rejects with a `BugseeAttributeError`. Match on its `code`, an `AttributeErrorCode` value:
+
+| `AttributeErrorCode` | `code` | Meaning |
+| --- | --- | --- |
+| `BadArgument` | `E_ATTRIBUTE_BAD_ARGUMENT` | The name or value failed validation in JavaScript; nothing was sent. |
+| `Rejected` | `E_ATTRIBUTE_REJECTED` | The value was not kept. Android: also when a read or clear call (`getAttribute`, `getAllAttributes`, `clearAttribute`, `clearAllAttributes`) failed. iOS: only `setAttribute` rejects with it; the read and clear calls always resolve. |
+
+```ts
+import Bugsee, { AttributeErrorCode, BugseeAttributeError } from '@bugsee/react-native';
+
+async function rememberNote(note: string): Promise {
+ try {
+ await Bugsee.setAttribute('note', note);
+ } catch (error) {
+ if (error instanceof BugseeAttributeError && error.code === AttributeErrorCode.Rejected) {
+ await Bugsee.setAttribute('note', note.slice(0, 500)); // too large for this platform
+ return;
+ }
+ throw error;
+ }
+}
+```
+
+Error messages never include the attribute's value.
+
+## Attributes on one report
+
+`Bugsee.setAttribute` applies to every report. To set an attribute on a single report, use the report's own `setAttribute` in a [report handler](/sdk/react_native/report-handler#changing-a-report), or `update` on a report from [`createReport`](/sdk/react_native/manual/bug-reporting#build-a-report-yourself).
+
+## Privacy
+
+The identifier and every attribute are sent with every report. Do not put passwords, tokens or other secrets in them, and keep personal data to what you need to find a user's reports. Clear them at sign-out, since attributes persist across launches. See [Privacy: Report](/sdk/react_native/privacy/report) for the other controls over what a report sends.
+
+## Related pages
+
+- [Custom events & traces](/sdk/react_native/events-and-traces): record what happened, and how values changed, on the report timeline.
+- [Report handler](/sdk/react_native/report-handler): change attributes on one report.
+- [Privacy: Report](/sdk/react_native/privacy/report): what a report sends.
diff --git a/docs/sdk/react_native/v6/configuration.mdx b/docs/sdk/react_native/v6/configuration.mdx
new file mode 100644
index 0000000..e18f1d7
--- /dev/null
+++ b/docs/sdk/react_native/v6/configuration.mdx
@@ -0,0 +1,168 @@
+---
+title: "Configuration"
+description: "Complete reference of Bugsee React Native launch options for iOS and Android, including recording, crash detection, network capture, and trigger settings."
+sidebar_position: 1
+slug: "/sdk/react_native/v6/configuration"
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+## Launching with options
+
+:::warning
+iOS/iPadOS: Since v6.0.0 the underlying Bugsee iOS SDK supports the simulator; crash capture is excluded. For full functionality, launch your app with Bugsee on a real device.
+:::
+
+Bugsee behavior is very customizable, if default configuration is not satisfying your needs you can launch the SDK with additional parameters. Use instance of ```IOSLaunchOptions``` or ```AndroidLaunchOptions``` for corresponding platform to change Bugsee behavior.
+
+
+
+
+
+```javascript
+import Bugsee from 'react-native-bugsee';
+
+// ...
+
+export default class App extends Component<{}> {
+ constructor(props) {
+ super(props);
+
+ const bugseeOptions = new Bugsee.IOSLaunchOptions();
+
+ bugseeOptions.shakeToReport = true;
+ bugseeOptions.reportPrioritySelector = true;
+ bugseeOptions.defaultBugPriority = Bugsee.BugseeSeverityLevel.Critical;
+
+ Bugsee.launch("", bugseeOptions);
+ }
+}
+```
+
+
+
+
+```javascript
+import Bugsee from 'react-native-bugsee';
+
+// ...
+
+export default class App extends Component<{}> {
+ constructor(props) {
+ super(props);
+
+ const bugseeOptions = new Bugsee.AndroidLaunchOptions();
+
+ bugseeOptions.shakeToTrigger = true;
+ bugseeOptions.notificationBarTrigger = false;
+
+ Bugsee.launch("", bugseeOptions);
+ }
+}
+```
+
+
+
+
+Note that when you launch Bugsee, it starts working in background with the specified launch options. Later, if you change launch options and reload JS layer, they will be ignored as Bugsee is already running. So, to workaround this, you should either relaunch the whole app or call Bugsee.relaunch() with the new launch options.
+
+
+### Available Options
+
+#### For iOS
+
+|Key|Default|Notes
+|---|---|---|
+|captureDeviceAndNetworkNames|false|Capture device name, wifi SSID and mobile carrier name.|
+|captureLogs|true|Automatically capture all console logs|
+|crashReport|true|Catch and report application crashes (\*)|
+|defaultBugPriority|High|Default priority for bugs|
+|defaultCrashPriority|Blocker|Default priority for crashes|
+|killDetection|false|Detect abnormal termination (experimental, [read more](/sdk/ios/app-kills/))|
+|maxRecordingTime|60|Maximum recording duration|
+|monitorNetwork|true|Capture network traffic|
+|reportPrioritySelector|false|Allow user to modify priority when reporting manually|
+|screenshotToReport|true|Screenshot key to trigger report|
+|shakeToReport|false|Shake gesture to trigger report|
+|style|Default|Enumeration of Default, Dark and BasedOnStatusBar
+|videoEnabled|true|Enable video recording|
+|frameRate|High|Specifies how often frames are captured|
+|screenshotEnabled|true|Attach screenshot to a report|
+|wifiOnlyUpload|false|Upload reports only when a device is connected to a WiFi network|
+|maxDataSize|50|Bugsee will avoid using more disk space than specified (in MB). If total Bugsee data size exceeds specified value, oldest recordings (even not sent) will be removed. Value should not be smaller than 10|
+
+:::warning
+* iOS allows only one crash detector to be active at a time, if you insist on using an alternative solution for handling crashes, you might want to use this option and disable Bugsee from taking over.
+:::
+
+
+#### For Android
+
+|Key|Default|Notes
+|---|---|---|
+|captureDeviceAndNetworkNames|true|Capture device name, wifi SSID and mobile carrier name.|
+|captureLogs|true|Automatically capture all console logs|
+|crashReport|true|Catch and report application crashes|
+|defaultBugPriority|High|Default priority for bugs|
+|defaultCrashPriority|Blocker|Default priority for crashes|
+|frameRate|High|Specifies how often frames are captured|
+|handleAnr|false|Detect ANR (Application Not Responding) and transform it to a meaningful exception|
+|logLevel|Verbose|Minimal log level of Logcat messages, which will be attached to report|
+|maxDataSize|50|Maximum disk space consumed by Bugsee|
+|maxRecordingTime|60|Maximum recording duration|
+|monitorNetwork|true|Capture network traffic|
+|notificationBarTrigger|true|Trigger report from notification bar|
+|screenshotToReport|false|Trigger bug report by taking screenshot on device. Bugsee React Native SDK 5.4.0 and up. This feature requires additional permissions: **Android 14+**: DETECT_SCREEN_CAPTURE permission is required. More details about the permission and the native API involved in [Android development documentation](https://developer.android.com/about/versions/14/features/screenshot-detection). **Android 13**: READ_MEDIA_IMAGES permission is required. **Android 12** and below: READ_EXTERNAL_STORAGE permission is required. On Android 13 and below, Bugsee SDK monitors the gallery to detect screenshot creation and that's why the permissions mentioned above are required.|
+|reportPrioritySelector|false|Allow user to modify priority when reporting manually|
+|screenshotEnabled|true|Attach screenshot to a report|
+|serviceMode|false|Used, when Bugsee is launched from service. No video and no visual controls available. Recording continues even in background.|
+|shakeToTrigger|false|Shake gesture to trigger report|
+|videoEnabled|true|Enable video recording|
+|videoMode|VideoMode.V3|Specifies video recording mode. Available options are: VideoMode.V1, VideoMode.V2, VideoMode.V3|
+|wifiOnlyUpload|false|Upload reports only when a device is connected to a WiFi network|
+
+
+## Stop, Relaunch
+It is also possible to relaunch Bugsee with other options later
+
+
+
+
+
+```javascript
+// Relaunch with other options.
+const options = new Bugsee.IOSLaunchOptions();
+
+// Set other launch options
+//...
+
+Bugsee.relaunch(options);
+```
+
+
+
+
+```javascript
+// Relaunch with other options.
+const options = new Bugsee.AndroidLaunchOptions();
+
+// Set other launch options
+//...
+
+Bugsee.relaunch(options);
+```
+
+
+
+
+or stop the events and video recording.
+
+```javascript
+// Stop recording completely
+Bugsee.stop()
+```
\ No newline at end of file
diff --git a/docs/sdk/react_native/crashes.mdx b/docs/sdk/react_native/v6/crashes.mdx
similarity index 92%
rename from docs/sdk/react_native/crashes.mdx
rename to docs/sdk/react_native/v6/crashes.mdx
index f63b2e6..a5b5b6a 100644
--- a/docs/sdk/react_native/crashes.mdx
+++ b/docs/sdk/react_native/v6/crashes.mdx
@@ -2,13 +2,17 @@
title: "Crash reports"
description: "How to configure automatic source map uploads and symbolication for readable JavaScript and native crash stack traces in React Native."
sidebar_position: 9
-slug: "/sdk/react_native/crashes"
+slug: "/sdk/react_native/v6/crashes"
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-Bugsee automatically intercepts uncaught exceptions and sends crash reports on app restart. Refer to [installation](/sdk/react_native/installation/) for more details. However, due to various optimizations, stack traces in these reports can be mangled. To make them human readable and point to correct code locations Bugsee requires additional debug information which should be collected and sent as described in this section.
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+Bugsee automatically intercepts uncaught exceptions and sends crash reports on app restart. Refer to [installation](/sdk/react_native/v6/installation/) for more details. However, due to various optimizations, stack traces in these reports can be mangled. To make them human readable and point to correct code locations Bugsee requires additional debug information which should be collected and sent as described in this section.
## Symbolication
diff --git a/docs/sdk/react_native/custom.md b/docs/sdk/react_native/v6/custom.md
similarity index 91%
rename from docs/sdk/react_native/custom.md
rename to docs/sdk/react_native/v6/custom.md
index 062ba00..410e62b 100644
--- a/docs/sdk/react_native/custom.md
+++ b/docs/sdk/react_native/v6/custom.md
@@ -2,9 +2,13 @@
title: "Adding custom data"
description: "Attach user email, custom events, traces, session attributes, and file attachments to Bugsee reports in React Native."
sidebar_position: 3
-slug: "/sdk/react_native/custom"
+slug: "/sdk/react_native/v6/custom"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
When you already have your users identified within your app, you might want to automatically attach their email to the bug report. Bugsee provides APIs for setting, getting, and clearing the email.
```javascript
diff --git a/docs/sdk/react_native/errorboundary.md b/docs/sdk/react_native/v6/errorboundary.md
similarity index 81%
rename from docs/sdk/react_native/errorboundary.md
rename to docs/sdk/react_native/v6/errorboundary.md
index c02154b..f8ad37f 100644
--- a/docs/sdk/react_native/errorboundary.md
+++ b/docs/sdk/react_native/v6/errorboundary.md
@@ -2,9 +2,13 @@
title: "React Error Boundary"
description: "Use Bugsee's ErrorBoundary component to automatically catch and report JavaScript errors thrown inside a React component tree."
sidebar_position: 10
-slug: "/sdk/react_native/errorboundary"
+slug: "/sdk/react_native/v6/errorboundary"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
The Bugsee React Native SDK exports an error boundary component that provides [React component APIs](https://reactjs.org/docs/error-boundaries.html) to automatically catch and send JavaScript errors from inside a React component tree to Bugsee
@@ -53,16 +57,16 @@ class App extends React.Component {
render() {
return (
(
+ fallback={({ error, componentStack, resetErrorBoundary }) => (
Error encountered
{error.toString()}
{componentStack}
{
this.setState({ message: DEFAULT_MESSAGE });
- {/* When resetError() is called, Fallback component will be removed */}
+ {/* When resetErrorBoundary() is called, Fallback component will be removed */}
{/* and Bugsee ErrorBoundary's children will be rendered in their initial state */}
- resetError();
+ resetErrorBoundary();
}}>Reset
)}
diff --git a/docs/sdk/react_native/v6/feedback.md b/docs/sdk/react_native/v6/feedback.md
new file mode 100644
index 0000000..4384ec0
--- /dev/null
+++ b/docs/sdk/react_native/v6/feedback.md
@@ -0,0 +1,28 @@
+---
+title: "Feedback"
+description: "Enable in-app user-to-support messaging in React Native by launching Bugsee's built-in feedback UI and configuring a default greeting."
+sidebar_position: 6
+slug: "/sdk/react_native/v6/feedback"
+---
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+Bugsee implements a built-in single-threaded messenger to allow your users to communicate with your support and developers.
+
+## Feedback activity
+
+To start feedback activity from within your application:
+
+```javascript
+Bugsee.showFeedbackUI();
+```
+
+## Default greeting
+
+Default greeting can be set on the server in your application settings. However, for the cases when network is not available, you can set default greeting on the client as well:
+
+```javascript
+Bugsee.setDefaultFeedbackGreeting("Hi! How can we help?");
+```
diff --git a/docs/sdk/react_native/installation.md b/docs/sdk/react_native/v6/installation.md
similarity index 88%
rename from docs/sdk/react_native/installation.md
rename to docs/sdk/react_native/v6/installation.md
index 906193d..8f9b716 100644
--- a/docs/sdk/react_native/installation.md
+++ b/docs/sdk/react_native/v6/installation.md
@@ -2,9 +2,13 @@
title: "React Native"
description: "Step-by-step guide to install the react-native-bugsee module and launch Bugsee from JavaScript or native code on iOS and Android."
sidebar_position: 0
-slug: "/sdk/react_native/installation"
+slug: "/sdk/react_native/v6/installation"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
:::info[Agent-Assisted Setup]
Ask your AI coding assistant:
@@ -44,7 +48,7 @@ cd ..
Download the latest version from [here](https://download.bugsee.com/sdk/ios/dynamic/Bugsee-stable.xcframework.zip) and extract it.
Copy ```Bugsee.xcframework``` to your project by drag and dropping it into the right location. When asked, choose to copy:
-
+
You can also use the instructions for native iOS applications from [here](/sdk/ios/installation/) to install the native part of the Bugsee SDK for React Native.
diff --git a/docs/sdk/react_native/lifecycle.md b/docs/sdk/react_native/v6/lifecycle.md
similarity index 84%
rename from docs/sdk/react_native/lifecycle.md
rename to docs/sdk/react_native/v6/lifecycle.md
index 63756f5..6698e69 100644
--- a/docs/sdk/react_native/lifecycle.md
+++ b/docs/sdk/react_native/v6/lifecycle.md
@@ -2,9 +2,13 @@
title: "Lifecycle events"
description: "Subscribe to Bugsee SDK lifecycle events in React Native to be notified when the SDK starts, stops, pauses, or uploads reports."
sidebar_position: 8
-slug: "/sdk/react_native/lifecycle"
+slug: "/sdk/react_native/v6/lifecycle"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
Bugsee SDK silently works within your app, recording everything to assist you in debugging when something unexpected happens. Our SDK is designed as a black box, but there may be cases when you want to be notified about changes/events within Bugsee itself. Lifecycle events are designed exactly for that. Whenever internal state changes or some important event is raised, a lifecycle event is dispatched to the user code.
## Implementing callback
diff --git a/docs/sdk/react_native/logs.md b/docs/sdk/react_native/v6/logs.md
similarity index 75%
rename from docs/sdk/react_native/logs.md
rename to docs/sdk/react_native/v6/logs.md
index cb7e48a..5807207 100644
--- a/docs/sdk/react_native/logs.md
+++ b/docs/sdk/react_native/v6/logs.md
@@ -2,9 +2,13 @@
title: "Logging"
description: "Integrate Bugsee with the React Native logging system and send custom log messages with explicit log levels from JavaScript."
sidebar_position: 4
-slug: "/sdk/react_native/logs"
+slug: "/sdk/react_native/v6/logs"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
Bugsee provides a way to hook Bugsee as custom logger to React Native logging system. With this, console.log(), console.warn(), console.error() as well
as React Native internal logs will be properly handled by Bugsee.
diff --git a/docs/sdk/react_native/manual.md b/docs/sdk/react_native/v6/manual.md
similarity index 77%
rename from docs/sdk/react_native/manual.md
rename to docs/sdk/react_native/v6/manual.md
index 27279e4..e2db4ae 100644
--- a/docs/sdk/react_native/manual.md
+++ b/docs/sdk/react_native/v6/manual.md
@@ -2,9 +2,13 @@
title: "Manual invocation"
description: "Programmatically trigger the bug report dialog, silently upload reports, and log non-fatal exceptions from React Native code."
sidebar_position: 2
-slug: "/sdk/react_native/manual"
+slug: "/sdk/react_native/v6/manual"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
## Trigger Report view
In addition to detection of a shake gesture or screenshot issue report view can be triggered programmatically from within
diff --git a/docs/sdk/react_native/network.md b/docs/sdk/react_native/v6/network.md
similarity index 70%
rename from docs/sdk/react_native/network.md
rename to docs/sdk/react_native/v6/network.md
index c37b9b6..de277a8 100644
--- a/docs/sdk/react_native/network.md
+++ b/docs/sdk/react_native/v6/network.md
@@ -2,9 +2,13 @@
title: "Network capture"
description: "Enable Bugsee network traffic capture in React Native, including the required Android OkHttp client factory setup."
sidebar_position: 7
-slug: "/sdk/react_native/network"
+slug: "/sdk/react_native/v6/network"
---
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
On both Android and iOS Bugsee is capable of capturing network events made either by your JS or platform code. On iOS we automatically install required hooks and no actions should be taken from user space. However, on Android, a single line should be added to the application bootstrap flow to let us intercept network events.
**Android**
diff --git a/docs/sdk/react_native/v6/privacy/logs.md b/docs/sdk/react_native/v6/privacy/logs.md
new file mode 100644
index 0000000..af563f0
--- /dev/null
+++ b/docs/sdk/react_native/v6/privacy/logs.md
@@ -0,0 +1,47 @@
+---
+title: "Privacy and console logs"
+description: "Disable or sanitize console log collection in React Native to prevent personally identifiable data from being included in Bugsee reports."
+sidebar_position: 3
+slug: "/sdk/react_native/v6/privacy/logs"
+---
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+## Disabling log collection
+
+Console log collection can be disabled completely by providing corresponding launch flags. Refer to [configuration](/sdk/react_native/v6/configuration/) and look for **captureLogs** launch option for more info.
+
+## Sanitizing console logs
+
+Bugsee automatically captures all standard application console logs, but they can be protected as well.
+
+For every event to be recorded, Bugsee will call your method and provide you with an object with captured data. It is your
+method's responsibility to clean up all user identifiable data from that structure and return it back to Bugsee.
+
+### Providing handler
+
+You should pass a callback to Bugsee.setLogFilter().
+
+```javascript
+Bugsee.setLogFilter(function (logEvent) {
+ // Filter log event here or return
+ // null to prevent it from being
+ // recorded at all
+ return logEvent;
+});
+
+// To stop using provided filter callback, just pass null
+Bugsee.setLogFilter(null);
+```
+
+### Logging Events
+
+The handler is going to be called one time for each logged message.
+
+
+|Property|Description|Type|Read only|Notes
+|---|---|---|---|---|
+|text|Text being logged|String|NO||
+|level|Logging level|Number|NO|1 - error, 2 - warning, 3 - info, 4 - debug, 5 - verbose|
\ No newline at end of file
diff --git a/docs/sdk/react_native/v6/privacy/network.md b/docs/sdk/react_native/v6/privacy/network.md
new file mode 100644
index 0000000..d69efcf
--- /dev/null
+++ b/docs/sdk/react_native/v6/privacy/network.md
@@ -0,0 +1,48 @@
+---
+title: "Privacy and Network traffic"
+description: "Disable or filter captured network requests and responses in React Native to strip sensitive data before it is recorded by Bugsee."
+sidebar_position: 2
+slug: "/sdk/react_native/v6/privacy/network"
+---
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+## Disabling network traffic collection
+
+Network traffic collection can be disabled completely by providing corresponding launch flags. Refer to [configuration](/sdk/react_native/v6/configuration/) and look for **monitorNetwork** launch option for more info.
+
+
+## Sanitizing data
+
+Bugsee captures network activity from the application and stores headers and in some cases body of the request and response.
+In order to allow you to hide user identifiable and other sensitive data from these network logs, we let you hook into network capturing by installing network filter handler that will be called for every event about to be recorded.
+
+For every event to be recorded, Bugsee will call your method and provide you with an object containing captured data. It is your method's responsibility to clean up all user identifiable data from that structure and return it back to Bugsee.
+
+```javascript
+Bugsee.setNetworkFilter(function (netEvent) {
+ // Filter event here as required, or return null to ignore it
+ return netEvent;
+});
+
+// To remove previously set network filter handler, just pass null to setNetworkFilter()
+Bugsee.setNetworkFilter(null);
+```
+
+### Network Events
+
+The handler is going to be called several times for each network request, depending on its life-cycle. Usually for
+successful requests it's going to be called twice, once with the request event (request headers and body) and once after
+completion and will contain headers and body of the response.
+
+
+|Property|Description|Type|Read only|Notes
+|---|---|---|---|---|
+|type|Type of network event|String|YES| 'begin', 'complete', 'cancel' or 'error'|
+|method|HTTP Request Method|String|YES|'GET', 'POST', etc...
+|url|Network event URL|String|NO|
+|redirected_from|URL of Network event that we were redirected from|String|NO|
+|body|Body|String|NO|Raw body of the request or response where available.
+|headers|HTTP Headers|Object|NO|Key-value map of HTTP headers associated with the event.|
\ No newline at end of file
diff --git a/docs/sdk/react_native/v6/privacy/overview.md b/docs/sdk/react_native/v6/privacy/overview.md
new file mode 100644
index 0000000..a85d869
--- /dev/null
+++ b/docs/sdk/react_native/v6/privacy/overview.md
@@ -0,0 +1,32 @@
+---
+title: "Privacy overview"
+description: "Overview of privacy considerations for Bugsee in React Native and the tools available to prevent or sanitize PII in reports."
+sidebar_position: 0
+slug: "/sdk/react_native/v6/privacy/overview"
+---
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+Bugsee SDK does not continuously stream any personal data. The reports are stored locally on the phone in a cyclical buffer. Reports are being sent only when triggered by a crash, through a bug reporting UI or from an application's code.
+Data sent along with the reports may include video recording of screen, network and console logs. These may potentially contain PII (Personally Identifiable Information).
+
+It is the sole responsibility of the application developers to remove any such data from the reports before it leaves the users’ device.
+
+Bugsee provides the tools and means to either prevent some data from being collected or clean the data during the collection process:
+
+* [Video and Touch](/sdk/react_native/v6/privacy/video/)
+* [Network](/sdk/react_native/v6/privacy/network/)
+* [Console logs](/sdk/react_native/v6/privacy/logs/)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/sdk/react_native/v6/privacy/video.md b/docs/sdk/react_native/v6/privacy/video.md
new file mode 100644
index 0000000..ec22763
--- /dev/null
+++ b/docs/sdk/react_native/v6/privacy/video.md
@@ -0,0 +1,72 @@
+---
+title: "Privacy and video"
+description: "Pause screen recording, mark UI components as protected, and define secure rectangles to hide sensitive content from Bugsee video in React Native."
+sidebar_position: 1
+slug: "/sdk/react_native/v6/privacy/video"
+---
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+# Going dark
+
+In some rare cases you might want to conceal the whole screen and stop recording events completely. The following APIs will come in handy, no data is being gathered between the calls to pause and resume.
+
+```javascript
+// To stop video recording use
+Bugsee.pause();
+
+// And to continue
+Bugsee.resume();
+```
+
+### Marking view as protected in code
+
+You can mark any view as protected and in this case it will be covered with a black box automatically. Use `Bugsee.toggleProtected()` method to achieve this. It accepts two parameters: `component` and `state`. First should be a reference to the component you want to hide/show and second is a boolean value of `protected` flag (either `true` or `false`).
+
+```jsx
+ this.setState({text})}
+ value={this.state.text} ref={comp => Bugsee.toggleProtected(comp, true)}
+/>
+```
+
+
+### Protecting by coordinates
+
+Bugsee allows hiding screen area by absolute coordinates as well. Notice that iOS and Android approaches to hiding specific area differ a bit.
+
+```javascript
+// Values are: X, Y, Width, Height
+Bugsee.addSecureRect(10, 10, 400, 600);
+```
+
+You also need to be aware of the orientation that can be changed while the app is running. Recreate rectangle after orientation change, if 'black box' on video does not cover all secure fields and elements.
+
+Other methods of secure rectangles:
+
+```javascript
+// Remove rect
+Bugsee.removeSecureRect(10, 10, 100, 100);
+
+// Get all rectangles
+const rectangles = await Bugsee.getAllSecureRects();
+
+// Remove all rectangles
+Bugsee.removeAllSecureRects();
+```
+
+
+## Hiding keyboard (iOS only)
+
+In some cases you might want to prevent the keyboard from being captured on video (as well as touches). You can use the following method to achieve the desired effect.
+
+```javascript
+// To let us capture keyboard
+Bugsee.setKeyboardVisibility(true);
+
+// To prevent keyboard from being captured
+Bugsee.setKeyboardVisibility(false);
+```
\ No newline at end of file
diff --git a/docs/sdk/react_native/v6/release-notes.md b/docs/sdk/react_native/v6/release-notes.md
new file mode 100644
index 0000000..7b9b908
--- /dev/null
+++ b/docs/sdk/react_native/v6/release-notes.md
@@ -0,0 +1,333 @@
+---
+title: "Release notes"
+description: "Changelog for the Bugsee React Native SDK listing new features, bug fixes, and breaking changes for each released version."
+sidebar_position: 11
+slug: "/sdk/react_native/v6/release-notes"
+---
+
+:::caution[Previous version]
+This page documents Bugsee React Native SDK **6.x** (`react-native-bugsee`), the current stable release. The new **7.x** SDK (`@bugsee/react-native`) is in beta: see [Migrating from 6.x to 7.x](/sdk/react_native/migration) to evaluate it, or the [7.x overview](/sdk/react_native/overview) to start a new integration.
+:::
+
+## 6.0.5 (August 18 2026)
+- Internal improvements.
+
+## 6.0.4 (July 31 2026)
+- Feat: Updated native SDKs to their latest versions (Android: [6.0.4](/sdk/android/v6/release-notes/#604-june-22-2026), iOS: [6.3.1](/sdk/ios/release-notes/#631-july-31-2026))
+
+## 6.0.3 (June 23 2026)
+- Feat: Updated native SDKs to their latest versions (Android: [6.0.4](/sdk/android/v6/release-notes/#604-june-22-2026), iOS: [6.1.2](/sdk/ios/release-notes/#612-march-4-2026))
+
+## 6.0.2 (March 20 2026)
+- Feat: Updated native SDKs to their latest versions (Android: [6.0.2](/sdk/android/v6/release-notes/#602-march-11-2026), iOS: [6.1.2](/sdk/ios/release-notes/#612-march-4-2026))
+
+## 6.0.0 (March 6 2026)
+- Feat: Updated native SDKs to their latest versions (Android: [6.0.0](/sdk/android/v6/release-notes/#600-december-9-2025), iOS: [6.1.2](/sdk/ios/release-notes/#612-march-4-2026))
+- Breaking: \[iOS\] Minimum deployment target is iOS 12.0
+- Breaking: \[Android\] Bugsee SDK is now built with Android SDK version 35, hence requires compileSDKVersion 35
+- Breaking: \[Android\] AGP 8.6.0 or newer is now required
+
+## 5.5.10 (November 18 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.9.1](/sdk/android/v6/release-notes/#591-september-29-2025), iOS: [5.5.9](/sdk/ios/release-notes/#559-november-17-2025))
+
+## 5.5.9 (October 15 2025)
+- Fix: \[Android\] In some scenarios, SDK may fail to launch
+
+## 5.5.8 (October 15 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.9.1](/sdk/android/v6/release-notes/#591-september-29-2025), iOS: [5.5.8](/sdk/ios/release-notes/#558-august-21-2025))
+
+## 5.5.7 (August 21 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.8.4](/sdk/android/v6/release-notes/#584-august-21-2025), iOS: [5.5.8](/sdk/ios/release-notes/#558-august-21-2025))
+
+## 5.5.6 (August 8 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.8.3](/sdk/android/v6/release-notes/#583-august-8-2025), iOS: [5.5.7](/sdk/ios/release-notes/#557-august-1-2025))
+
+## 5.5.5 (August 7 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.8.2](/sdk/android/v6/release-notes/#582-august-7-2025), iOS: [5.5.7](/sdk/ios/release-notes/#557-august-1-2025))
+
+## 5.5.4 (June 12 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.7.5](/sdk/android/v6/release-notes/#575-june-8-2025), iOS: [5.5.6](/sdk/ios/release-notes/#556-march-25-2025))
+- Fix: \[Android\] In some configurations, application may crash on device with 16KB memory pages
+
+## 5.5.3 (May 6 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.7.3](/sdk/android/v6/release-notes/#573-may-5-2025), iOS: [5.5.6](/sdk/ios/release-notes/#556-march-25-2025))
+
+## 5.5.2 (March 10 2025)
+- Fix: Build failure on Android
+- Feat: Updated native SDKs to their latest versions (Android: [5.7.2](/sdk/android/v6/release-notes/#572-march-17-2025), iOS: [5.5.6](/sdk/ios/release-notes/#556-march-25-2025))
+
+## 5.5.1 (March 10 2025)
+- Feat: Add option to enable native crashes interception in Android SDK (NdkCrashReport)
+
+## 5.5.0 (March 10 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.7.1](/sdk/android/v6/release-notes/#571-march-4-2025), iOS: [5.5.5](/sdk/ios/release-notes/#555-february-13-2025))
+- Feat: React Native "New architecture" support
+
+## 5.4.3 (February 4 2025)
+- Feat: Updated native SDKs to their latest versions (Android: [5.6.5](/sdk/android/v6/release-notes/#565-february-3-2025), iOS: [5.5.4](/sdk/ios/release-notes/#554-january-27-2025))
+- Fix: \[Android\] Built-in UI shifts upwards in some scenarios on Android 15 (specifically, when hosting application itself is targeting Android 15, i.e. target SDK version is 35)
+
+## 5.4.2 (January 22 2025)
+- Fix: \[Android\] Network requests may not complete when custom networking libraries are used
+
+## 5.4.1 (January 14 2025)
+- Fix: \[Android\] Ensure Bugsee notification entry is displayed right away when runtime notification permission is granted from within application
+
+## 5.4.0 (January 9 2025)
+- Feat: Updated native SDKs to their latest versions (Android: 5.6.1, iOS: 5.5.3)
+- Feat: Add support for bug reporting via screenshot gesture on Android
+
+## 5.3.0 (September 12 2024)
+- Feat: Updated native SDKs to their latest versions (Android: 5.4.2, iOS: 5.3.2)
+- Feat: \[Android\] Add support for 16KB memory pages
+- Fix: \[Android\] Crash when bug is sent from built-in reporting UI after removing screenshot
+
+## 5.2.0 (September 2 2024)
+- Feat: Updated native SDKs to their latest versions (Android: 5.3.1, iOS: 5.3.2)
+
+## 5.1.2 (May 08 2024)
+- Fix: \[Android\] Video may be absent on some devices with Unisoc chipsets
+
+## 5.1.1 (April 19 2024)
+- Fix: \[Android\] In some cases, video before FG->BG->FG transitions may be absent
+- Note: \[Android\] compileSdkVersion 34 and up is now required
+
+## 5.1.0 (April 19 2024)
+- Note: Broken release, please update to 5.1.1 or later
+
+## 5.0.4 (April 18 2024)
+- Fix: Sourcemaps were not uploaded properly in some cases for Android
+
+## 5.0.3 (April 11 2024)
+- Feat: Updated native SDKs to their latest versions (Android: 4.2.4, iOS: 5.0.2)
+
+## 5.0.2 (April 2 2024)
+- Fix: "handleRejections" launch option may not be respected in some cases
+
+## 5.0.1 (March 21 2024)
+- Feat: Updated native SDKs to their latest versions (Android: 4.2.4, iOS: 5.0.0)
+
+## 5.0.0 (December 25 2023)
+- Feat: Updated native SDKs to their latest versions (Android: 4.2.1, iOS: 5.0.0)
+- Breaking: \[iOS\] Bitcode is not present in the resulting binaries any more
+
+## 4.1.0 (December 6 2023)
+- Feat: Updated native SDKs to their latest versions (Android: 4.2.1, iOS: 4.1.0)
+
+## 4.0.0 (October 2 2023)
+- Feat: Updated native SDKs to their latest versions (Android: [4.0.1](/sdk/android/v6/release-notes/#401-september-30-2023), iOS: [4.0.1](/sdk/ios/release-notes/#401-september-30-2023))
+- Breaking: Changes for the underlying SDKs: [Android](/sdk/android/v6/release-notes/#401-september-30-2023) and [iOS](/sdk/ios/release-notes/#401-september-30-2023).
+
+## 3.2.0 (September 1 2023)
+- Feat: Updated native SDKs to their latest versions (Android: 3.10.0, iOS: 3.8.0)
+- Feat: Add new API to manually trigger view hierarchy capturing. Multiple view hierarchies support.
+
+## 3.1.3 (August 4 2023)
+- Feat: Updated underlying Android SDKs to their latest version (3.8.3)
+- Fix: \[Android\] Deadlock in some specific scenario when application comes to foreground
+
+## 3.1.2 (July 12 2023)
+- Feat: Updated native SDKs to their latest versions (Android: 3.8.2, iOS: 3.7.1)
+- Fix: \[Android\] In some circumstances crashes may not be reported
+
+## 3.1.1 (June 20 2023)
+- Fix: Issue with logException() on iOS
+
+## 3.1.0 (June 12 2023)
+- Fix: Properly respect MonitorNetwork option during relaunch
+
+## 3.0.10 (February 26 2023)
+- Feature: Update native SDKs to the latest versions (Android: 3.4.0, iOS: 3.3.3)
+
+## 3.0.9 (February 14 2023)
+- Fix: Crash when attachment data contained non-text value (e.g. object, array, etc)
+
+## 3.0.8 (January 26 2023)
+- Feature: Update native SDKs to the latest versions (Android: 3.4.0, iOS: 3.3.2)
+- Fix: \[Android\] Video was disabled on some Samsung devices due to the restrictive internal checks
+
+## 3.0.7 (January 24 2023)
+- Fix: Workaround for a bug in React Native build script which caused source maps collection failure
+
+## 3.0.6 (January 23 2023)
+- Fix: Incorrect selector in iOS bridging module may cause build errors
+
+## 3.0.5 (January 20 2023)
+- Feature: Update native SDKs to the latest versions (Android: 3.3.0, iOS: 3.3.2)
+
+## 3.0.4 (December 7 2022)
+- Fix: Some async exceptions were not properly handled which caused missing video and data in the consequent bug/error/crash reports
+- Feature: Update native SDKs to the latest versions (Android: 3.1.0, iOS: 3.3.1)
+
+## 3.0.3 (November 28 2022)
+- Feature: Update native SDKs to the latest versions (Android: 3.0.2, iOS: 3.2.1)
+
+## 3.0.2 (October 5 2022)
+- Feature: Add fallbacks for Gradle properties (compileSdkVersion, targetSdkVersion, buildToolsVersion)
+
+## 3.0.1 (October 4 2022)
+- Fix: Messages sent to Bugsee.log() may not be registered properly
+
+## 3.0.0 (September 19 2022)
+- Feature: Update native SDKs to the latest versions (Android: 3.0.0, iOS: 3.0.0)
+- Feature: Reworked debugging information uploading mechanism (source maps uploading) which is now fully automatic
+- Note: Please refer to the underlying SDKs release notes to get the detailed list of changes: [Android](/sdk/android/v6/release-notes/#300-august-19-2022) / [iOS](/sdk/ios/release-notes/#300-september-1-2022)
+
+## 2.10.3 (June 1 2022)
+- Feature: Updated native Android SDKs to their latest versions. Several race conditions are fixed
+
+## 2.10.2 (May 11 2022)
+- Feature: Updated native Android/iOS SDKs to their latest versions
+
+## 2.10.1 (April 28 2022)
+- Feature: Updated native Android/iOS SDKs to their latest versions
+
+## 2.10.0 (April 14 2022)
+- Feature: Updated native Android/iOS SDKs to their latest versions
+
+## 2.9.1 (March 22 2022)
+- Fix: Some network events were not captured properly when network filter was set (on Android)
+
+## 2.9.0 (March 16 2022)
+- Feature: Updated native iOS SDKs to their latest version
+- Feature: Clean script is not required any more for iOS project
+
+## 2.8.0 (February 04 2022)
+- Feature: Updated native iOS SDKs to their latest version
+- Feature: iOS SDK is not bundled within the NPM package any more, but rather is fetched via CocoaPods
+
+## 2.7.0 (January 26 2022)
+- Feature: Updated native SDKs to its newer versions.
+- Fix \[iOS\]: Crash during video capture in some specific conditions
+
+## 2.6.1 (November 12 2021)
+- Feature: Improve exception information handling for better symbolication of JS call stacks
+
+## 2.6.0 (October 4 2021)
+- Feature: Updated native Android SDKs to their latest versions. They include full support for iOS 15 and Android 12
+
+## 2.5.1 (August 12 2021)
+- Feature: Automatically generate stack trace when non-Error instance is supplied to logException
+
+## 2.5.0 (August 3 2021)
+- Feature: Updated native Android SDKs to their latest versions. It includes many updates to embedded dependencies to mitigate the NonSdkApi warnings and errors.
+
+## 2.4.6 (June 18 2021)
+- Fix: Add missing reporting UI controlling flags to launch options
+
+## 2.4.5 (June 17 2021)
+- Fix: In some rare cases launch options may not be sent to the underlying SDKs correctly
+
+## 2.4.4 (June 13 2021)
+- Fix: Properly handle symbolication result from built-in symbolicator
+
+## 2.4.3 (June 8 2021)
+- Feature: Updated native SDKs to their latest versions
+- Feature: Add video fallback mode launch option for Android
+
+## 2.4.2 (May 17 2021)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.4.1 (April 20 2021)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.4.0 (February 24 2021)
+- Feature: Updated native SDKs to their latest versions
+- Feature: Improve autolinking support
+
+## 2.3.8 (February 10 2021)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.3.7 (November 10 2020)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.3.6 (August 31 2020)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.3.5 (August 11 2020)
+- Feature: Updated native Android SDK to its latest version \[1.19.0\]
+
+## 2.3.4 (June 9 2020)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.3.3 (April 14 2020)
+- Fix: Rare crash when using ref statements and node is not found
+
+## 2.3.2 (June 7 2020)
+- Feature: Updated native SDKs to their latest versions
+
+## 2.3.1 (April 7 2020)
+- Fix: Update native SDK, to disable on-device symbolication by default to prevent application crash \[iOS\]
+
+## 2.2.2 (February 25 2020)
+- Feature: Update native SDKs
+
+## 2.2.1 (June 27 2019)
+- Fix: Memory leak in report controller (iOS)
+
+## 2.2.0 (June 21 2019)
+- Feature: Add option to control bluetooth state monitoring (iOS)
+- Feature: Add support for lifecycle events
+
+## 2.0.14 (Mar 27 2019)
+- Fix: Update iOS SDK to the latest version to fix a rare crash during view hierarchy capturing
+
+## 2.0.13 (Mar 15 2019)
+- Fix: Updated Android SDK to the latest version containing the fix for touch interception
+
+## 2.0.12 (Mar 11 2019)
+- Feature: Expose methods to trigger JS and native crashes manually
+
+## 2.0.9 - 2.0.11 (Mar 4 2019)
+- Fix: Correctly define and use Launch options in index.ts file
+
+## 2.0.8 (Jan 29 2019)
+- Fix: Properly check for Podfile presence during linking to prevent failure
+
+## 2.0.1 - 2.0.7 (Jan 14 2019)
+- Fix: Duplicate iOS crash/error reports
+- Fix: Some crashes do not merge properly
+- Fix: Fix automatic Bugsee iOS SDK module linking (via 'react-native link')
+- Other minor improvements
+
+## 2.0.1 (Jan 1 2019)
+- Fix: Update iOS SDK to 1.19.1 to prevent app crashing in some cases. For more info look [here](/sdk/ios/release-notes/)
+
+## 2.0.0 (December 26 2018)
+- Feature: Much easier installation and initialization (via 'react-native link')
+- Feature: New module design. Now everything can be controlled from JS
+- Feature: Add support for custom attachments
+- Feature: New exceptions capturing mechanism
+
+## 1.1.0 (May 31 2018)
+- Feature: Network and console logs filters (privacy)
+- Feature: Enable/disable keyboard capture (privacy, iOS-only)
+- Feature: Secure rectangles. Allows explicitly specify area which must be concealed from recording.
+- Feature: Source maps. Added support for source maps to properly symbolicate stack traces for minified JS sources.
+
+## 1.0.8 (Aug 31 2017)
+- Maintenance and bug-fix release.
+
+## 1.0.7 (Apr 11 2017)
+- Maintenance and bug-fix release.
+
+## 1.0.6 (Mar 7 2017)
+- Maintenance and bug-fix release.
+
+## 1.0.5 (Mar 4 2017)
+- Maintenance and bug-fix release.
+
+## 1.0.4 (Mar 4 2017)
+- Maintenance and bug-fix release.
+
+## 1.0.3 (Dec 16 2016)
+- Maintenance and bug-fix release.
+
+## 1.0.2 (Oct 13 2016)
+- Maintenance and bug-fix release.
+
+## 1.0.1 (Sep 14 2016)
+- Maintenance and bug-fix release.
+
+## 1.0.0 (Sep 14 2016)
+- Initial release
\ No newline at end of file
diff --git a/docusaurus.config.ts b/docusaurus.config.ts
index 508ccd4..047b1d9 100644
--- a/docusaurus.config.ts
+++ b/docusaurus.config.ts
@@ -102,6 +102,20 @@ const config: Config = {
{ from: '/sdk/android/v7/detection', to: '/sdk/android/issue-detection/' },
{ from: '/sdk/android/v7/extensions', to: '/sdk/android/extensibility/bugsee-extensions/' },
{ from: '/sdk/android/v7/manual', to: '/sdk/android/manual/bug-reporting/' },
+ // React Native 6.x pages moved under /sdk/react_native/v6/; old routes with no 7.x page keep their 6.x content.
+ { from: '/sdk/react_native/custom', to: '/sdk/react_native/v6/custom/' },
+ { from: '/sdk/react_native/crashes', to: '/sdk/react_native/v6/crashes/' },
+ { from: '/sdk/react_native/errorboundary', to: '/sdk/react_native/v6/errorboundary/' },
+ { from: '/sdk/react_native/manual', to: '/sdk/react_native/v6/manual/' },
+ // The hyphenated spelling is generated only for pages that exist, so the retired routes need it explicitly.
+ { from: '/sdk/react-native/custom', to: '/sdk/react_native/v6/custom/' },
+ { from: '/sdk/react-native/crashes', to: '/sdk/react_native/v6/crashes/' },
+ { from: '/sdk/react-native/errorboundary', to: '/sdk/react_native/v6/errorboundary/' },
+ { from: '/sdk/react-native/manual', to: '/sdk/react_native/v6/manual/' },
+ { from: '/sdk/react-native/v6', to: '/sdk/react_native/v6/installation/' },
+ { from: '/sdk/react-native/v6/privacy', to: '/sdk/react_native/v6/privacy/overview/' },
+ { from: '/sdk/react_native/v6', to: '/sdk/react_native/v6/installation/' },
+ { from: '/sdk/react_native/v6/privacy', to: '/sdk/react_native/v6/privacy/overview/' },
],
// Android 7.x lived under /sdk/android/v7/ until it became the default;
// every current Android page keeps answering at its old v7 address.
diff --git a/sidebars.ts b/sidebars.ts
index 7340430..6dd7d00 100644
--- a/sidebars.ts
+++ b/sidebars.ts
@@ -546,10 +546,32 @@ const sidebars: SidebarsConfig = {
label: "React Native SDK",
collapsed: true,
items: [
+ {
+ type: "link",
+ label: "Stable release (6.x) docs",
+ href: "/sdk/react_native/v6/installation",
+ },
{
type: "doc",
- id: "sdk/react_native/installation",
- label: "Installation",
+ id: "sdk/react_native/overview",
+ label: "Overview",
+ },
+ {
+ type: "category",
+ label: "Installation & Invocation",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "sdk/react_native/installation",
+ label: "Installation",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/expo",
+ label: "Expo",
+ },
+ ],
},
{
type: "doc",
@@ -558,11 +580,68 @@ const sidebars: SidebarsConfig = {
},
{
type: "doc",
- id: "sdk/react_native/manual",
- label: "Manual invocation",
+ id: "sdk/react_native/lifecycle",
+ label: "Lifecycle & status",
+ },
+ {
+ type: "category",
+ label: "Manual reporting",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "sdk/react_native/manual/bug-reporting",
+ label: "Bug reporting",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/manual/crash-error-reporting",
+ label: "Crash & error reporting",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/error-boundary",
+ label: "Error boundary",
+ },
+ ],
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/report-handler",
+ label: "Report handler",
+ },
+ {
+ type: "category",
+ label: "Data capture",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "sdk/react_native/network",
+ label: "Network events",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/logs",
+ label: "Console logs",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/breadcrumbs",
+ label: "Breadcrumbs",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/events-and-traces",
+ label: "Custom events & traces",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/user-session-data",
+ label: "User & session data",
+ },
+ ],
},
- { type: "doc", id: "sdk/react_native/custom", label: "Custom data" },
- { type: "doc", id: "sdk/react_native/logs", label: "Console logs" },
{
type: "category",
label: "Privacy",
@@ -578,6 +657,11 @@ const sidebars: SidebarsConfig = {
id: "sdk/react_native/privacy/video",
label: "Video",
},
+ {
+ type: "doc",
+ id: "sdk/react_native/privacy/logs",
+ label: "Console logs",
+ },
{
type: "doc",
id: "sdk/react_native/privacy/network",
@@ -585,33 +669,151 @@ const sidebars: SidebarsConfig = {
},
{
type: "doc",
- id: "sdk/react_native/privacy/logs",
- label: "Console logs",
+ id: "sdk/react_native/privacy/breadcrumbs",
+ label: "Breadcrumbs",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/privacy/report",
+ label: "Report",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/privacy/cleanup",
+ label: "Cleanup",
},
],
},
- { type: "doc", id: "sdk/react_native/feedback", label: "Feedback" },
{
type: "doc",
- id: "sdk/react_native/network",
- label: "Network capture",
+ id: "sdk/react_native/feedback",
+ label: "Feedback",
},
{
type: "doc",
- id: "sdk/react_native/lifecycle",
- label: "Lifecycle events",
+ id: "sdk/react_native/notification-relay",
+ label: "Notification relay",
},
- { type: "doc", id: "sdk/react_native/crashes", label: "Crash reports" },
{
type: "doc",
- id: "sdk/react_native/errorboundary",
- label: "Error boundary",
+ id: "sdk/react_native/appearance",
+ label: "Appearance",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/performance",
+ label: "Performance monitoring",
+ },
+ {
+ type: "category",
+ label: "Symbolication",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "sdk/react_native/symbolication/overview",
+ label: "Overview",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/symbolication/android",
+ label: "Android",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/symbolication/ios",
+ label: "iOS",
+ },
+ ],
},
{
type: "doc",
id: "sdk/react_native/release-notes",
label: "Release notes",
},
+ {
+ type: "doc",
+ id: "sdk/react_native/faq",
+ label: "FAQ",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/migration",
+ label: "Migrating from 6.x",
+ },
+ {
+ type: "category",
+ label: "Previous versions",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/installation",
+ label: "Installation",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/configuration",
+ label: "Configuration",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/manual",
+ label: "Manual invocation",
+ },
+ { type: "doc", id: "sdk/react_native/v6/custom", label: "Custom data" },
+ { type: "doc", id: "sdk/react_native/v6/logs", label: "Console logs" },
+ {
+ type: "category",
+ label: "Privacy",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/privacy/overview",
+ label: "Overview",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/privacy/video",
+ label: "Video",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/privacy/network",
+ label: "Network",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/privacy/logs",
+ label: "Console logs",
+ },
+ ],
+ },
+ { type: "doc", id: "sdk/react_native/v6/feedback", label: "Feedback" },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/network",
+ label: "Network capture",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/lifecycle",
+ label: "Lifecycle events",
+ },
+ { type: "doc", id: "sdk/react_native/v6/crashes", label: "Crash reports" },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/errorboundary",
+ label: "Error boundary",
+ },
+ {
+ type: "doc",
+ id: "sdk/react_native/v6/release-notes",
+ label: "Release notes",
+ },
+ ],
+ },
],
},
{