Skip to content

feat(network-details): Extend SentryReplayOptions API with Session Replay Network Details configuration#7580

Open
43jay wants to merge 3 commits intomainfrom
mobile-935/sdk-options
Open

feat(network-details): Extend SentryReplayOptions API with Session Replay Network Details configuration#7580
43jay wants to merge 3 commits intomainfrom
mobile-935/sdk-options

Conversation

@43jay
Copy link
Collaborator

@43jay 43jay commented Mar 3, 2026

Implement SDK fields, setters and validation for network details capture: https://docs.sentry.io/platforms/javascript/session-replay/configuration/#network-details

Key Type Default Description
networkDetailAllowUrls (string|RegExp)[] [] Capture request and response details for XHR and fetch requests that match the given URLs.
networkDetailDenyUrls (string|RegExp)[] [] Do not capture request and response details for these URLs. Takes precedence over networkDetailAllowUrls.
networkCaptureBodies boolean true Decide whether to capture request and response bodies for URLs defined in networkDetailAllowUrls.
networkRequestHeaders string[] [] Additional request headers to capture for URLs defined in networkDetailAllowUrls.
networkResponseHeaders string[] [] Additional response headers to capture for URLs defined in networkDetailAllowUrls.

networkDetail[Allow|Deny]Urls

  • When client specifies a string => used for substring matching

E.g., "example.com" matches "api.example.com"

  • When client specifies a regex => used for NSRegularExpression#firstMatch
  • networkDetailDenyUrls takes precedence over networkDetailAllowUrls
  • Empty string filtering to handle invalid input gracefully

network[Request|Response]Headers

  • Default headers are always extracted and can't be disabled - "Content-Type", "Content-Length", "Accept"
  • The header literal seen on the request is extracted (not the header name provided via SentryReplayOptions)
  • header comparison is case-insensitive (see PR 5/8)

networkCaptureBodies

  • nm, just a boolean.

📜 Description

PR 1/N. Extend SentryReplayOptions API with Session Replay Network Details configuration
PR 2/N. Adds test app UI to configure and test network details collection.
PR 3/N. Adds data holder classes to define structure of data being extracted
PR 4/N. Adds new swizzling introduced to capture response bodies.
PR 5/N. Implements extraction logic for headers & bodies.
PR 6/N. Hook into existing SentryNetworkTracker.m|h
PR 7/N. Implement conversion from breadcrumb data -> Session Replay compatible RRWebEvent

💡 Motivation and Context

Parent issue (android, cocoa, RN) - getsentry/sentry#84596
Cocoa sub-issue - #4944

This PR adds the SDK fields required for developers to enable network details extraction for network requests made during a session replay capture, by following the impl in sentry-javascript and sentry-java (android).

💚 How did you test it?

Unit tests

SentryReplayOptionsTests

xcodebuild test -workspace Sentry.xcworkspace -scheme Sentry -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:SentryTests/SentryReplayOptionsTests

    ✔ testInitFromDict_networkCaptureBodies_whenValidValue_shouldSetValue (0.000 seconds)
    ✔ testInitFromDict_networkCaptureBodies_withNSNumber_shouldConvertCorrectly (0.000 seconds)
    ✔ testInitFromDict_networkDetailAllowUrls_whenValidValue_shouldSetValue (0.000 seconds)
    ✔ testInitFromDict_networkDetailDenyUrls_whenInvalidValue_shouldUseDefaultValue (0.000 seconds)
    ✔ testInitFromDict_networkDetailDenyUrls_whenValidValue_shouldSetValue (0.000 seconds)
    ✔ testInitFromDict_networkRequestHeaders_whenInvalidArrayValue_shouldFilterInvalidValues (0.000 seconds)
    ✔ testInitFromDict_networkRequestHeaders_whenInvalidValue_shouldUseDefaultValue (0.000 seconds)
    ✔ testInitFromDict_networkRequestHeaders_whenValidValue_shouldSetValue (0.000 seconds)
    ✔ testInitFromDict_networkResponseHeaders_whenInvalidArrayValue_shouldFilterInvalidValues (0.000 seconds)
    ✔ testInitFromDict_networkResponseHeaders_whenInvalidValue_shouldUseDefaultValue (0.000 seconds)
    ✔ testInitFromDict_networkResponseHeaders_whenValidValue_shouldSetValue (0.000 seconds)

SentryReplayOptionsNetworkTests
Additional unit tests for network details (I didn't put them in SentryReplayOptionsTests to avoid over-crowding that file / I assumed SentryReplayOptionsTests should be for high level testing of SentryReplayOptions).

xcodebuild test -workspace Sentry.xcworkspace -scheme Sentry -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:SentryTests/SentryReplayOptionsNetworkTests 2>&1 | xcbeautify

    ✔ testInit_withInvalidTypes_shouldUseDefaults (0.003 seconds)
    ✔ testIsNetworkDetailCaptureEnabled_withBasicAllowDenyLogic_shouldReturnCorrectResults (0.000 seconds)
    ✔ testIsNetworkDetailCaptureEnabled_withRegexPatterns_shouldMatchCorrectly (0.002 seconds)
    ✔ testNetworkDetailUrls_withEmptyStrings_shouldFilterOutEmptyEntries (0.001 seconds)
    ✔ testNetworkDetailUrls_withInvalidTypes_shouldFilterOutInvalidEntries (0.003 seconds)
    ✔ testNetworkDetailUrls_withMixedStringAndRegexTypes_shouldMatchCorrectly (0.000 seconds)
    ✔ testNetworkHeaders_withCaseInsensitiveDuplicates_shouldPreventDuplicateHeaders (0.001 seconds)
    ✔ testNetworkHeaders_withCustomHeaders_shouldAlwaysIncludeDefaultHeaders (0.001 seconds)
    ✔ testNetworkHeaders_withVariousCases_shouldDeduplicateCaseInsensitively (0.000 seconds)
    ✔ testNetworkHeaders_withVariousConfigurations_shouldHandleCorrectly (0.000 seconds)

SentryReplayOptionsObjcTests
ObjC <> Swift compatibility tests. Mostly for Regex matching

xcodebuild test -workspace Sentry.xcworkspace -scheme Sentry -destination 'platform=iOS
Simulator,name=iPhone 16 Pro' -only-testing:SentryTests/SentryReplayOptionsObjcTests

    ✔ testInit_withAllArguments_shouldSetAllValues (0.002 seconds)
    ✔ testInit_withoutArguments_shouldUseDefaults (0.001 seconds)
    ✔ testIsNetworkDetailCaptureEnabled_withDenyPatterns_shouldRespectDenyOverAllow (0.001 seconds)
    ✔ testIsNetworkDetailCaptureEnabled_withMixedPatterns_shouldSupportBoth (0.000 seconds)
    ✔ testIsNetworkDetailCaptureEnabled_withNSRegularExpression_shouldUseProvidedRegexMatching (0.000 seconds)
    ✔ testIsNetworkDetailCaptureEnabled_withStringPatterns_shouldUseSubstringMatching (0.000 seconds)

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled. Nothing extracted in this PR - SDKOptions available but no backing implementation.
  • I updated the docs if needed. Docs updated when CHANGELOG goes in
  • I updated the wizard if needed. No wizard updates
  • Review from the native team if needed. N/A
  • No breaking change or entry added to the changelog. future PR #skip-changelog
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs. Extends API -> nothing breaking expected.

@43jay 43jay self-assigned this Mar 3, 2026
@linear
Copy link

linear bot commented Mar 3, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against cfc450a

Implement SDK fields, setters and validation for network details capture:
 https://docs.sentry.io/platforms/javascript/session-replay/configuration/#network-details

- String patterns for prefix matching (e.g., "https://api.example.com" matches subpaths)
- NSRegularExpression patterns for complex regex matching
- Deny list precedence over allow list
- Empty string filtering to handle invalid input gracefully
@43jay 43jay force-pushed the mobile-935/sdk-options branch from 1d2a165 to 8e08354 Compare March 3, 2026 19:03
@43jay 43jay marked this pull request as ready for review March 3, 2026 19:05
@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 98.70130% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 85.393%. Comparing base (f194b9c) to head (cfc450a).
⚠️ Report is 9 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...tegrations/SessionReplay/SentryReplayOptions.swift 98.461% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7580       +/-   ##
=============================================
+ Coverage   85.328%   85.393%   +0.064%     
=============================================
  Files          483       485        +2     
  Lines        28750     28823       +73     
  Branches     12489     12529       +40     
=============================================
+ Hits         24532     24613       +81     
+ Misses        4170      4163        -7     
+ Partials        48        47        -1     
Files with missing lines Coverage Δ
Sources/Swift/Protocol/SentryUrlMatchable.swift 100.000% <100.000%> (ø)
Sources/Swift/Protocol/SentryUrlMatcher.swift 100.000% <100.000%> (ø)
...tegrations/SessionReplay/SentryReplayOptions.swift 97.267% <98.461%> (+0.573%) ⬆️

... and 12 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f194b9c...cfc450a. Read the comment docs.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: URL pattern validation runs twice on dictionary init
    • I removed pre-validation in the dictionary initializer and routed raw values to the private initializer so URL patterns are validated exactly once in a single source of truth.

Create PR

Or push these changes by commenting:

@cursor push 95c595cf60
Preview (95c595cf60)
diff --git a/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift b/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift
--- a/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift
+++ b/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift
@@ -601,8 +601,8 @@
             maximumDuration: (dictionary["maximumDuration"] as? NSNumber)?.doubleValue,
             excludedViewClasses: (dictionary["excludedViewClasses"] as? [String]).map { Set($0) },
             includedViewClasses: (dictionary["includedViewClasses"] as? [String]).map { Set($0) },
-            networkDetailAllowUrls: Self.validateNetworkDetailUrlPatterns(from: dictionary["networkDetailAllowUrls"]),
-            networkDetailDenyUrls: Self.validateNetworkDetailUrlPatterns(from: dictionary["networkDetailDenyUrls"]),
+            networkDetailAllowUrls: dictionary["networkDetailAllowUrls"],
+            networkDetailDenyUrls: dictionary["networkDetailDenyUrls"],
             networkCaptureBodies: (dictionary["networkCaptureBodies"] as? NSNumber)?.boolValue,
             networkRequestHeaders: Self.parseStringArray(from: dictionary["networkRequestHeaders"]),
             networkResponseHeaders: Self.parseStringArray(from: dictionary["networkResponseHeaders"])
@@ -745,8 +745,8 @@
         maximumDuration: TimeInterval?,
         excludedViewClasses: Set<String>? = nil,
         includedViewClasses: Set<String>? = nil,
-        networkDetailAllowUrls: [Any]? = nil,
-        networkDetailDenyUrls: [Any]? = nil,
+        networkDetailAllowUrls: Any? = nil,
+        networkDetailDenyUrls: Any? = nil,
         networkCaptureBodies: Bool? = nil,
         networkRequestHeaders: [String]? = nil,
         networkResponseHeaders: [String]? = nil
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Copy link
Member

@philprime philprime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good progress, almost LGTM

* - Note: Request and response bodies are truncated to 150KB maximum.
* - Note: See ``SentryReplayOptions.DefaultValues.networkDetailAllowUrls`` for the default value.
*/
public var networkDetailAllowUrls: [Any]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: This might be a great opportunity to use protocol-based such as we did in SentryMetricsApiProtocol where the attributes are actually just the protocol [SentryAttributeValue]https://github.com/getsentry/sentry-cocoa/blob/main/Sources/Swift/Protocol/SentryAttributeValue.swift#L46)

If not we could also consider using enums with associated values instead of type-erasing it. See these two blog posts for context:

Might not work with Objective-C though

Copy link
Collaborator Author

@43jay 43jay Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion. i took a crack at it. PTAL

Might not work with Objective-C though

The only oddity i needed was introducing an objC getter for networkDetailAllowUrls and networkDetailDenyUrls ... an oddity b/c the getters are currently only called from SentryReplayOptionsObjcTests so it's odd to have them hanging around on the SentryReplayOptions.swift API (and i couldn't see a way to hide them).

43jay added 2 commits March 4, 2026 13:51
…URL filtering

Replace [Any] with [SentryUrlMatchable] for networkDetailAllowUrls/DenyUrls.
Provides compile-time type safety in Swift while maintaining Objective-C
compatibility through bridge properties.

Follows the API pattern of SentryAttributeValue/Content.
@43jay 43jay requested a review from philprime March 4, 2026 21:18
@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1215.11 ms 1250.19 ms 35.08 ms
Size 24.14 KiB 1.13 MiB 1.10 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
93ef486 1220.22 ms 1244.96 ms 24.74 ms
4883c74 1224.80 ms 1258.65 ms 33.85 ms
19f3e6b 1231.17 ms 1257.02 ms 25.85 ms
21cd5ba 1218.68 ms 1255.54 ms 36.86 ms
2f4ddaa 1227.26 ms 1260.04 ms 32.78 ms
37bc095 1210.00 ms 1242.69 ms 32.69 ms
41cc629 1222.58 ms 1253.09 ms 30.51 ms
b984142 1222.18 ms 1257.77 ms 35.59 ms
d29a425 1209.96 ms 1239.00 ms 29.04 ms
18c94be 1218.26 ms 1258.80 ms 40.54 ms

App size

Revision Plain With Sentry Diff
93ef486 24.14 KiB 1.06 MiB 1.04 MiB
4883c74 24.14 KiB 1.12 MiB 1.10 MiB
19f3e6b 24.14 KiB 1.10 MiB 1.08 MiB
21cd5ba 24.14 KiB 1.04 MiB 1.02 MiB
2f4ddaa 24.14 KiB 1.04 MiB 1.02 MiB
37bc095 24.14 KiB 1.06 MiB 1.04 MiB
41cc629 24.14 KiB 1.12 MiB 1.10 MiB
b984142 24.14 KiB 1.11 MiB 1.09 MiB
d29a425 24.14 KiB 1.04 MiB 1.02 MiB
18c94be 24.14 KiB 1.10 MiB 1.08 MiB

Copy link
Contributor

@itaybre itaybre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost LGTM, just some small comments

And you will need to run make generate-public-api due to the new public APIs

* - Note: This setting only applies when ``networkDetailAllowUrls`` is non-empty.
* - Note: Header names preserve the case seen on the request, not the case specified here.
*/
public var networkRequestHeaders: [String] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m" This API won't be available for ObjC?

* - Note: This setting only applies when ``networkDetailAllowUrls`` is non-empty.
* - Note: Header names preserve the case seen on the response, not the case specified here.
*/
public var networkResponseHeaders: [String] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Same question as above, not available for ObjC?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants