From 6c5c928db68bd31a4d25382b7a44f8b00a689150 Mon Sep 17 00:00:00 2001 From: Alexey Karimov Date: Tue, 20 Oct 2026 22:16:09 +0500 Subject: [PATCH 1/4] Document network filter scope and the per-platform built-in redaction difference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #137. The wrapper passes the native filters through; routing breadcrumb/span URLs through the network filter and running the iOS built-in sanitizer ahead of the JS filter are native SDK changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- packages/react-native/README.md | 30 ++++++++++++++++++++++++++++++ packages/react-native/src/index.ts | 10 +++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/react-native/README.md b/packages/react-native/README.md index 7c54836e..b67bbcf2 100644 --- a/packages/react-native/README.md +++ b/packages/react-native/README.md @@ -290,6 +290,36 @@ so when the root file already has one the pin goes into it (its braces must stand alone on their lines, or the prebuild refuses); a new block is written only when there is none. +## Network privacy + +`Bugsee.setNetworkFilter` sees network events, and only network events. Two +things differ from what you might assume. Both are behavior of the native +SDKs, which this package passes through unchanged. + +- **Built-in redaction differs by platform.** On Android the built-in + sanitizer runs before your filter (when + `com.bugsee.option.capture.network.default-sanitizer` is on). On iOS an + installed filter replaces the built-in sanitizer, so raw events reach it + and anything it does not remove is recorded. Built-in header matching also + differs: iOS matches a fixed list of names, Android also matches substrings + such as `session`, `token` and `secret`. Write the filter as if it were + the only redaction. +- **The filter does not reach every place a URL is recorded.** URLs also + appear in HTTP breadcrumbs, in `http.client` performance spans (with + performance monitoring on, the default) and in the `http_url` attribute of + `detect.http-errors` reports. The network filter is not applied to them. + Platform behavior differs: Android applies the built-in sanitizer to span + URLs, iOS applies only built-in query sanitization to breadcrumb URLs and + none to span URLs. If URLs can carry secrets, redact them at the source + (do not put secrets in URLs), use `setBreadcrumbFilter` for breadcrumbs, or + turn off the capture you do not want, such as breadcrumbs or performance + monitoring. + +Routing these URLs through the network filter, and running the built-in +sanitizer ahead of the filter on iOS, needs changes in the native SDKs and +is tracked in +[#137](https://github.com/bugsee/bugsee-react-native/issues/137). + ## Release symbolication A Release build has to send Bugsee what turns its crash frames back into diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index c2927092..8a22291a 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -450,7 +450,15 @@ class Bugsee { * * A JS filter replaces the iOS built-in sanitizer. Android runs the * default sanitizer before the callback when - * `com.bugsee.option.capture.network.default-sanitizer` is on. + * `com.bugsee.option.capture.network.default-sanitizer` is on. Raw events + * therefore reach the filter on iOS, and what it does not remove is + * recorded. The built-in header matching also differs by platform. + * + * This filter sees network events only. It is not applied to the URLs in + * HTTP breadcrumbs, `http.client` performance spans (performance + * monitoring, on by default) or the `http_url` attribute of + * `detect.http-errors` reports. Redact those separately, or turn the + * capture off. See "Network privacy" in the package README. */ setNetworkFilter(callback?: NetworkFilter | null): void { installNetworkFilter(callback); From 494647717d930432065f89ca11638be8df164b89 Mon Sep 17 00:00:00 2001 From: Alexey Karimov Date: Tue, 20 Oct 2026 22:21:31 +0500 Subject: [PATCH 2/4] Correct network privacy docs after SDK review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- packages/react-native/README.md | 52 +++++++++++++++++------------- packages/react-native/src/index.ts | 24 +++++++------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/packages/react-native/README.md b/packages/react-native/README.md index b67bbcf2..213937d0 100644 --- a/packages/react-native/README.md +++ b/packages/react-native/README.md @@ -292,28 +292,36 @@ only when there is none. ## Network privacy -`Bugsee.setNetworkFilter` sees network events, and only network events. Two -things differ from what you might assume. Both are behavior of the native -SDKs, which this package passes through unchanged. - -- **Built-in redaction differs by platform.** On Android the built-in - sanitizer runs before your filter (when - `com.bugsee.option.capture.network.default-sanitizer` is on). On iOS an - installed filter replaces the built-in sanitizer, so raw events reach it - and anything it does not remove is recorded. Built-in header matching also - differs: iOS matches a fixed list of names, Android also matches substrings - such as `session`, `token` and `secret`. Write the filter as if it were - the only redaction. -- **The filter does not reach every place a URL is recorded.** URLs also - appear in HTTP breadcrumbs, in `http.client` performance spans (with - performance monitoring on, the default) and in the `http_url` attribute of - `detect.http-errors` reports. The network filter is not applied to them. - Platform behavior differs: Android applies the built-in sanitizer to span - URLs, iOS applies only built-in query sanitization to breadcrumb URLs and - none to span URLs. If URLs can carry secrets, redact them at the source - (do not put secrets in URLs), use `setBreadcrumbFilter` for breadcrumbs, or - turn off the capture you do not want, such as breadcrumbs or performance - monitoring. +`Bugsee.setNetworkFilter` sees network events, and only network events. +Write it as if it were your only redaction. + +- **Built-in redaction differs by platform.** On Android this package runs the + built-in sanitizer on each event before your filter (when + `com.bugsee.option.capture.network.default-sanitizer` is on). On iOS your + filter replaces the built-in sanitizer, so raw events reach it and anything + it does not remove is recorded. The built-in rules differ too. iOS matches a + fixed set of header names plus fixed query and body keys, and does not strip + credentials from URLs. Android also matches substrings such as `password`, + `secret`, `token`, `session` and `apikey` in header, query and body keys, + strips `user:password` from URLs and redacts error messages. +- **The filter does not reach every place a URL is recorded:** + - **HTTP breadcrumbs** (only when `captureBreadcrumbs` is enabled). Android + records the URL unredacted, without even the built-in query redaction. + iOS applies the built-in query redaction when `default-sanitizer` is on. + Use `setBreadcrumbFilter` to clean them. + - **`http.client` performance spans** (performance monitoring, + `com.bugsee.option.performance.enabled`, is on by default). Android always + applies its built-in sanitizer to span URLs, even with `default-sanitizer` + off. iOS applies no sanitization to span URLs. To turn them off: + + ```ts + const options = createDefaultLaunchOptions(); + options.setCustomOption('com.bugsee.option.performance.enabled', false); + ``` + + - **`detect.http-errors` reports** (off by default) carry the request URL in + `http_url` without its query or fragment. Path segments are not passed + through your filter. Routing these URLs through the network filter, and running the built-in sanitizer ahead of the filter on iOS, needs changes in the native SDKs and diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index 8a22291a..a9261316 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -448,17 +448,19 @@ class Bugsee { * filter; JS answers on a later turn, and a callback that throws, * rejects, or never settles drops the event. * - * A JS filter replaces the iOS built-in sanitizer. Android runs the - * default sanitizer before the callback when - * `com.bugsee.option.capture.network.default-sanitizer` is on. Raw events - * therefore reach the filter on iOS, and what it does not remove is - * recorded. The built-in header matching also differs by platform. - * - * This filter sees network events only. It is not applied to the URLs in - * HTTP breadcrumbs, `http.client` performance spans (performance - * monitoring, on by default) or the `http_url` attribute of - * `detect.http-errors` reports. Redact those separately, or turn the - * capture off. See "Network privacy" in the package README. + * On Android this package runs the built-in sanitizer on each event + * before the callback, when + * `com.bugsee.option.capture.network.default-sanitizer` is on. On iOS the + * callback replaces the built-in sanitizer, so raw events reach it and + * what it does not remove is recorded. The built-in rules also differ by + * platform. + * + * This filter sees network events only. It is not applied to URLs in HTTP + * breadcrumbs (when breadcrumb capture is on) or `http.client` performance + * spans (on by default), and path segments in the `http_url` attribute of + * `detect.http-errors` reports (off by default) are not passed through it. + * Redact breadcrumbs with {@link setBreadcrumbFilter}, or turn the capture + * off. See "Network privacy" in the package README. */ setNetworkFilter(callback?: NetworkFilter | null): void { installNetworkFilter(callback); From c479e592c2d0371ed806dcfd3ab8f2a8e2c7d886 Mon Sep 17 00:00:00 2001 From: Alexey Karimov Date: Wed, 21 Oct 2026 10:20:46 +0500 Subject: [PATCH 3/4] README: show a breadcrumb filter that strips URL queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- packages/react-native/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/react-native/README.md b/packages/react-native/README.md index 213937d0..23860cc7 100644 --- a/packages/react-native/README.md +++ b/packages/react-native/README.md @@ -308,7 +308,19 @@ Write it as if it were your only redaction. - **HTTP breadcrumbs** (only when `captureBreadcrumbs` is enabled). Android records the URL unredacted, without even the built-in query redaction. iOS applies the built-in query redaction when `default-sanitizer` is on. - Use `setBreadcrumbFilter` to clean them. + Use `setBreadcrumbFilter` to clean them. Return the whole crumb, because a + reply that leaves out a key the crumb had drops it. The URL is in `data` + on `http` crumbs: + + ```ts + Bugsee.setBreadcrumbFilter(crumb => { + const data = crumb.data as { url?: unknown } | null | undefined; + if (crumb.type !== 'http' || typeof data?.url !== 'string') { + return crumb; + } + return { ...crumb, data: { ...data, url: data.url.split(/[?#]/)[0] } }; + }); + ``` - **`http.client` performance spans** (performance monitoring, `com.bugsee.option.performance.enabled`, is on by default). Android always applies its built-in sanitizer to span URLs, even with `default-sanitizer` From f7974ea19620599ddd6d1766f3e3cc372e4dd52d Mon Sep 17 00:00:00 2001 From: Alexey Karimov Date: Wed, 21 Oct 2026 11:27:40 +0500 Subject: [PATCH 4/4] README: breadcrumb example also strips URL credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- packages/react-native/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/react-native/README.md b/packages/react-native/README.md index 23860cc7..cea5b26e 100644 --- a/packages/react-native/README.md +++ b/packages/react-native/README.md @@ -313,12 +313,16 @@ Write it as if it were your only redaction. on `http` crumbs: ```ts + // Drops user:password@, the query and the fragment. + const stripUrl = (url: string) => + url.replace(/\/\/[^/?#@]*@/, '//').split(/[?#]/)[0]; + Bugsee.setBreadcrumbFilter(crumb => { const data = crumb.data as { url?: unknown } | null | undefined; if (crumb.type !== 'http' || typeof data?.url !== 'string') { return crumb; } - return { ...crumb, data: { ...data, url: data.url.split(/[?#]/)[0] } }; + return { ...crumb, data: { ...data, url: stripUrl(data.url) } }; }); ``` - **`http.client` performance spans** (performance monitoring,