Skip to content

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

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

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

Conversation

@43jay
Copy link
Copy Markdown
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

(77 tests - showing last 30)

  Test Case '-[SentryTests.SentryReplayOptionsTests testInitFromDict_unmaskedViewClasses_whenInvalidArrayValues_shouldUseDefaultValue]' 
  passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testInitFromDict_unmaskedViewClasses_whenKeyOmitted_shouldUseDefaultValue]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests
  testInitFromDict_unmaskedViewClasses_whenMixedValidAndInvalidValues_shouldKeepOnlyValidValues]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testInitFromDict_unmaskedViewClasses_whenMultipleValidValue_shouldKeepAll]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testInitFromDict_unmaskedViewClasses_whenNotValidValue_shouldUseDefaultValue]' 
  passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testInitFromDict_unmaskedViewClasses_whenValidValue_shouldSetValue]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testInitFromDict_withMultipleOptions_shouldSetAllValues]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQuality_fromName_shouldParseKnownValues]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQuality_fromName_shouldReturnMediumForUnknownValues]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQualityFromName]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQualityFromName_invalidValue_shouldReturnDefaultQuality]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQualityHigh]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQualityLow]' passed
  Test Case '-[SentryTests.SentryReplayOptionsTests testQualityMedium]' passed
  Executed 77 tests, with 0 failures (0 unexpected)

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

 Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testIsNetworkDetailCaptureEnabled_withAllowList_shouldMatchCorrectly]' passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testIsNetworkDetailCaptureEnabled_withDenyList_shouldDenyMatchingUrls]'
  passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testIsNetworkDetailCaptureEnabled_withRegexPatterns_shouldMatchCorrectly]'
  passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkDetailUrls_withEmptyStrings_shouldFilterOutEmptyEntries]' passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkDetailUrls_withInvalidTypes_shouldFilterOutInvalidEntries]' passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkDetailUrls_withLeadingAndTrailingWhitespace_shouldTrimAndMatch]'
  passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkDetailUrls_withMixedStringAndRegexTypes_shouldMatchCorrectly]'
  passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests
  testNetworkHeaders_withCaseInsensitiveDuplicates_shouldPreventDuplicateHeaders]' passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkHeaders_withCustomHeaders_shouldAlwaysIncludeDefaultHeaders]'
  passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkHeaders_withVariousCases_shouldDeduplicateCaseInsensitively]'
  passed
  Test Case '-[SentryTests.SentryReplayOptionsNetworkTests testNetworkHeaders_withVariousConfigurations_shouldHandleCorrectly]' passed
  Executed 11 tests, with 0 failures (0 unexpected)

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

  Test Case '-[SentryReplayOptionsObjcTests testInit_withAllArguments_shouldSetAllValues]' passed
  Test Case '-[SentryReplayOptionsObjcTests testInit_withoutArguments_shouldUseDefaults]' passed
  Test Case '-[SentryReplayOptionsObjcTests testIsNetworkDetailCaptureEnabled_withDenyPatterns_shouldRespectDenyOverAllow]' passed
  Test Case '-[SentryReplayOptionsObjcTests testIsNetworkDetailCaptureEnabled_withMixedPatterns_shouldSupportBoth]' passed
  Test Case '-[SentryReplayOptionsObjcTests testIsNetworkDetailCaptureEnabled_withNSRegularExpression_shouldUseProvidedRegexMatching]'
  passed
  Test Case '-[SentryReplayOptionsObjcTests testIsNetworkDetailCaptureEnabled_withStringPatterns_shouldUseSubstringMatching]' passed
  Executed 6 tests, with 0 failures (0 unexpected)

📝 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
Copy Markdown

linear bot commented Mar 3, 2026

@github-actions
Copy link
Copy Markdown
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
Copy Markdown
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 cad52c2

@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
Copy Markdown

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.391%. Comparing base (8d00197) to head (cad52c2).
✅ 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   86.173%   85.391%   -0.783%     
=============================================
  Files          483       485        +2     
  Lines        28785     28859       +74     
  Branches     12504     12546       +42     
=============================================
- Hits         24805     24643      -162     
- Misses        3927      4170      +243     
+ Partials        53        46        -7     
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 11 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 8d00197...cad52c2. Read the comment docs.

Copy link
Copy Markdown

@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.

Autofix Details

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
Copy Markdown
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

@43jay 43jay requested a review from philprime March 4, 2026 21:18
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 4, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1215.13 ms 1253.09 ms 37.97 ms
Size 24.14 KiB 1.13 MiB 1.10 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
39fbc4b 1230.95 ms 1257.53 ms 26.58 ms
4c93fb8 1218.40 ms 1249.93 ms 31.53 ms
99e74a3 1203.33 ms 1248.57 ms 45.24 ms
d52e416 1209.02 ms 1239.56 ms 30.53 ms
16b3235 1234.51 ms 1257.84 ms 23.33 ms
11cad11 1208.65 ms 1250.88 ms 42.23 ms
2e5230b 1207.41 ms 1240.41 ms 33.00 ms
83bf9af 1213.30 ms 1234.18 ms 20.89 ms
1c9a029 1198.93 ms 1233.94 ms 35.00 ms
fe6228d 1215.81 ms 1234.04 ms 18.23 ms

App size

Revision Plain With Sentry Diff
39fbc4b 24.14 KiB 1.12 MiB 1.09 MiB
4c93fb8 24.14 KiB 1.11 MiB 1.09 MiB
99e74a3 24.14 KiB 1.12 MiB 1.09 MiB
d52e416 24.14 KiB 1.04 MiB 1.02 MiB
16b3235 24.14 KiB 1.11 MiB 1.09 MiB
11cad11 24.14 KiB 1.12 MiB 1.10 MiB
2e5230b 24.14 KiB 1.04 MiB 1.02 MiB
83bf9af 24.14 KiB 1.04 MiB 1.02 MiB
1c9a029 24.14 KiB 1.10 MiB 1.07 MiB
fe6228d 24.14 KiB 1.11 MiB 1.08 MiB

Previous results on branch: mobile-935/sdk-options

Startup times

Revision Plain With Sentry Diff
340b451 1205.93 ms 1225.39 ms 19.45 ms
56fb666 1215.11 ms 1250.19 ms 35.08 ms
2816207 1228.90 ms 1259.46 ms 30.56 ms

App size

Revision Plain With Sentry Diff
340b451 24.14 KiB 1.13 MiB 1.10 MiB
56fb666 24.14 KiB 1.13 MiB 1.10 MiB
2816207 24.14 KiB 1.12 MiB 1.10 MiB

Copy link
Copy Markdown
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

@43jay 43jay force-pushed the mobile-935/sdk-options branch from cfc450a to 1d0cc82 Compare March 9, 2026 19:02
@sentry
Copy link
Copy Markdown

sentry bot commented Mar 9, 2026

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

@43jay 43jay force-pushed the mobile-935/sdk-options branch from 1d0cc82 to 037f0e4 Compare March 9, 2026 19:48
Copy link
Copy Markdown

@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 is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@sentry
Copy link
Copy Markdown

sentry bot commented Mar 9, 2026

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

@43jay
Copy link
Copy Markdown
Collaborator Author

43jay commented Mar 9, 2026

Almost LGTM, just some small comments

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

@itaybre ran make generate-public api here

... seems like it picked up a bunch of arbitrary stuff (not sure, didn't look too hard). P sure i'll need to rebase and run it again

Copy link
Copy Markdown
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.

Almost LGTM

43jay added 3 commits March 10, 2026 14:45
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
…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.
…hables

Already implemented in SentryUrlMatcher.convertFromAny, and the new impl
had a bug flagged by SentryBot:

#7580 (comment)
@43jay 43jay force-pushed the mobile-935/sdk-options branch from 037f0e4 to cad52c2 Compare March 10, 2026 21:06
@sentry
Copy link
Copy Markdown

sentry bot commented Mar 10, 2026

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

43jay added 2 commits March 16, 2026 14:35
#7580 (comment)

Full ObjC support deferred to #7598.

Added SentryReplayOptions#networkDetailHasUrls computed property for:
  1) Confirming the feature is disabled in objc (see
      SentryReplayOptionsObjcTests.m)
  2) Using higher up in stack (see SentryRRWebOptionsEvent,
      SentryNetworkTrackingIntegration.swift)
(ammend 1) re-run upon removal of objc networkDetailAllow|DenyUrls bridge
@43jay 43jay force-pushed the mobile-935/sdk-options branch from cad52c2 to 83310fd Compare March 16, 2026 20:31
Copy link
Copy Markdown
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.

LGTM

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