Skip to content

Add deeplinkIntegration for automatic deep link breadcrumbs#5983

Merged
alwx merged 11 commits intomainfrom
alwx/improvement/deeplink-5424
Apr 14, 2026
Merged

Add deeplinkIntegration for automatic deep link breadcrumbs#5983
alwx merged 11 commits intomainfrom
alwx/improvement/deeplink-5424

Conversation

@alwx
Copy link
Copy Markdown
Contributor

@alwx alwx commented Apr 13, 2026

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

Introduces a new deeplinkIntegration that automatically captures breadcrumbs whenever the app is opened or foregrounded via a deep link.
Closes #5424

📝 Checklist

  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing
  • No breaking changes

🔮 Next steps

Introduces a new `deeplinkIntegration` that automatically captures breadcrumbs
whenever the app is opened or foregrounded via a deep link.

- Intercepts cold-start links via `Linking.getInitialURL()`
- Intercepts warm-open links via `Linking.addEventListener('url', ...)`
- Breadcrumbs use `category: 'deeplink'` and `type: 'navigation'`
- Respects `sendDefaultPii`: when false, query strings are stripped and
  numeric / UUID / long-hex path segments are replaced with `<id>`
- Compatible with both Expo Router and plain React Navigation deep linking
  (uses the standard RN `Linking` API, no framework-specific dependencies)
- Gracefully skips setup when Linking is unavailable (e.g. web)

Closes #5424
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

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


  • Add deeplinkIntegration for automatic deep link breadcrumbs by alwx in #5983
  • fix(core): Retry native module resolution to prevent silent event drops by antonis in #5981
  • feat(core): Name navigation spans using dispatched action payload by alwx in #5982
  • ci: Gate size analysis on ready-to-merge label for PRs by antonis in #5963
  • chore(deps): update Android SDK to v8.38.0 by github-actions in #5971
  • chore(deps): update Sentry Android Gradle Plugin to v6.4.0 by github-actions in #5974
  • chore(deps): update Cocoa SDK to v9.10.0 by github-actions in #5972
  • chore(deps): update JavaScript SDK to v10.48.0 by github-actions in #5975
  • chore(deps): bump actions/github-script from 8 to 9 by dependabot in #5980
  • chore(deps): bump actions/create-github-app-token from 3.0.0 to 3.1.1 by dependabot in #5979
  • chore(deps): update Bundler Plugins to v5.2.0 by github-actions in #5968
  • chore(deps): bump axios from 1.13.5 to 1.15.0 by dependabot in #5978
  • chore(deps): bump addressable from 2.8.7 to 2.9.0 in /performance-tests by dependabot in #5969
  • chore(deps): bump basic-ftp from 5.2.0 to 5.2.2 by dependabot in #5977
  • fix(profiling): Fix app start transaction profile timestamp offset by antonis in #5962
  • fix(android): Use componentStack as fallback for missing error stack traces by antonis in #5965
  • chore(deps): bump addressable from 2.8.7 to 2.9.0 in /samples/react-native-macos by dependabot in #5967
  • chore(deps): bump addressable from 2.8.7 to 2.9.0 in /samples/react-native by dependabot in #5966
  • fix(ios): Add SENTRY_PROJECT_ROOT env var for monorepo support by antonis in #5961
  • feat(ios): Add attachAllThreads option by antonis in #5960
  • fix(core): Lazy-load Metro internal modules to prevent Expo 55 import errors by lucas-zimerman in #5958
  • chore(deps): update Cocoa SDK to v9.9.0 by github-actions in #5956
  • chore(deps): update Maestro to v2.4.0 by github-actions in #5955
  • Feat: Fallback to stacktrace parsing by lucas-zimerman in #5946

Plus 8 more


🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

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

Generated by 🚫 dangerJS against 6e295a9

@alwx alwx self-assigned this Apr 13, 2026
@alwx alwx changed the title feat(core): Add deeplinkIntegration for automatic deep link breadcrumbs WIP: Add deeplinkIntegration for automatic deep link breadcrumbs Apr 13, 2026
@alwx alwx marked this pull request as ready for review April 14, 2026 09:06
@alwx alwx changed the title WIP: Add deeplinkIntegration for automatic deep link breadcrumbs Add deeplinkIntegration for automatic deep link breadcrumbs Apr 14, 2026
@alwx
Copy link
Copy Markdown
Contributor Author

alwx commented Apr 14, 2026

@cursor review

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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 560ceb9. Configure here.

- Strip URL fragments (#) in addition to query strings when sendDefaultPii
  is off, preventing PII leaks via fragment identifiers
- Store the Linking event listener subscription and remove it on client
  close to prevent resource leaks and duplicate breadcrumbs on hot reload
- Cache getBreadcrumbUrl result to avoid redundant getClient lookups and
  regex sanitization
- Extract RNLinking and LinkingSubscription interfaces for cleaner types
- Add tests for fragment stripping, combined query+fragment stripping,
  and subscription cleanup on client close
…linkIntegration

Replace the duplicated stripQueryAndFragment/sanitizeUrl logic with the
existing exported sanitizeUrl from tracing/utils.ts, which already strips
query strings and fragments. The deeplink-specific ID replacement regex
is kept in a new sanitizeDeepLinkUrl wrapper.
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.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1a19735. Configure here.

Copy link
Copy Markdown
Contributor

@antonis antonis left a comment

Choose a reason for hiding this comment

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

Other that the two issues flagged by the bots and the lint failure LGTM!

…kIntegration

- Split URL into authority and path before applying ID-replacement regex
  so hostnames that resemble hex strings (e.g. myapp://deadbeef/...) are
  not incorrectly replaced with <id>
- Move subscription to the factory closure and remove it on repeated
  setup calls to prevent duplicate listeners when Sentry.init() is
  called more than once
- Add tests for hostname preservation and repeated setup cleanup
@alwx alwx added the ready-to-merge Triggers the full CI test suite label Apr 14, 2026
@alwx alwx requested a review from antonis April 14, 2026 10:24
…compiled output

The local variable 'Linking' from tryGetLinking() collided with the
destructured 'Linking' from require('react-native') in the compiled JS,
causing a 'Duplicate declaration' build error. Renamed to 'linking'.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1222.12 ms 1220.94 ms -1.19 ms
Size 3.38 MiB 4.76 MiB 1.38 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
5c1e987+dirty 1204.30 ms 1222.15 ms 17.85 ms
2c735cc+dirty 1229.67 ms 1221.50 ms -8.17 ms
df5d108+dirty 1225.90 ms 1220.14 ms -5.76 ms
4953e94+dirty 1212.06 ms 1214.83 ms 2.77 ms
3ce5254+dirty 1219.93 ms 1221.90 ms 1.96 ms
3817909+dirty 1183.90 ms 1187.50 ms 3.60 ms
a50b33d+dirty 1197.74 ms 1197.17 ms -0.57 ms
04207c4+dirty 1191.27 ms 1189.78 ms -1.48 ms

App size

Revision Plain With Sentry Diff
5c1e987+dirty 3.38 MiB 4.73 MiB 1.35 MiB
2c735cc+dirty 3.38 MiB 4.74 MiB 1.35 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
4953e94+dirty 3.38 MiB 4.73 MiB 1.35 MiB
3ce5254+dirty 3.38 MiB 4.76 MiB 1.38 MiB
3817909+dirty 3.38 MiB 4.73 MiB 1.35 MiB
a50b33d+dirty 3.38 MiB 4.73 MiB 1.35 MiB
04207c4+dirty 3.38 MiB 4.76 MiB 1.38 MiB

@sentry
Copy link
Copy Markdown

sentry bot commented Apr 14, 2026

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
Sentry RN io.sentry.reactnative.sample 8.7.0 (82) Release

⚙️ sentry-react-native Build Distribution Settings

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1220.74 ms 1230.96 ms 10.21 ms
Size 3.38 MiB 4.76 MiB 1.38 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
5c1e987+dirty 1208.43 ms 1220.72 ms 12.29 ms
2c735cc+dirty 1223.33 ms 1224.38 ms 1.04 ms
df5d108+dirty 1207.34 ms 1210.50 ms 3.16 ms
4953e94+dirty 1217.41 ms 1223.53 ms 6.12 ms
3ce5254+dirty 1217.70 ms 1224.69 ms 6.99 ms
3817909+dirty 1210.76 ms 1215.64 ms 4.89 ms
a50b33d+dirty 1207.11 ms 1212.10 ms 5.00 ms
04207c4+dirty 1228.55 ms 1226.04 ms -2.51 ms

App size

Revision Plain With Sentry Diff
5c1e987+dirty 3.38 MiB 4.73 MiB 1.35 MiB
2c735cc+dirty 3.38 MiB 4.74 MiB 1.35 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
4953e94+dirty 3.38 MiB 4.73 MiB 1.35 MiB
3ce5254+dirty 3.38 MiB 4.76 MiB 1.38 MiB
3817909+dirty 3.38 MiB 4.73 MiB 1.35 MiB
a50b33d+dirty 3.38 MiB 4.73 MiB 1.35 MiB
04207c4+dirty 3.38 MiB 4.76 MiB 1.38 MiB

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 373.82 ms 413.68 ms 39.86 ms
Size 43.94 MiB 48.99 MiB 5.05 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3ce5254+dirty 373.90 ms 427.84 ms 53.94 ms
4953e94+dirty 398.80 ms 431.81 ms 33.01 ms
2c735cc+dirty 435.20 ms 459.48 ms 24.28 ms
3817909+dirty 357.52 ms 391.52 ms 34.00 ms
df5d108+dirty 434.82 ms 447.39 ms 12.57 ms
04207c4+dirty 395.40 ms 456.55 ms 61.15 ms
a50b33d+dirty 353.21 ms 398.48 ms 45.27 ms
5c1e987+dirty 444.71 ms 475.13 ms 30.42 ms

App size

Revision Plain With Sentry Diff
3ce5254+dirty 43.94 MiB 48.98 MiB 5.04 MiB
4953e94+dirty 43.94 MiB 48.94 MiB 5.00 MiB
2c735cc+dirty 43.94 MiB 48.94 MiB 5.00 MiB
3817909+dirty 43.94 MiB 48.94 MiB 5.00 MiB
df5d108+dirty 43.94 MiB 48.94 MiB 5.00 MiB
04207c4+dirty 43.94 MiB 48.98 MiB 5.04 MiB
a50b33d+dirty 43.94 MiB 48.94 MiB 5.00 MiB
5c1e987+dirty 43.94 MiB 48.94 MiB 5.00 MiB

@alwx alwx requested a review from antonis April 14, 2026 13:06
…lay-stubs.jar

- Rename destructured Linking to rnLinking inside tryGetLinking to avoid
  Babel/Metro duplicate declaration errors in compiled output
- Fix getInitialURL call chain formatting per lint
- Revert unrelated replay-stubs.jar binary change
@alwx alwx requested a review from antonis April 14, 2026 13:43
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 407.60 ms 418.72 ms 11.12 ms
Size 43.75 MiB 48.13 MiB 4.37 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3ce5254+dirty 410.57 ms 448.48 ms 37.91 ms
4953e94+dirty 442.02 ms 456.52 ms 14.50 ms
2c735cc+dirty 414.09 ms 438.47 ms 24.38 ms
3817909+dirty 406.67 ms 416.58 ms 9.91 ms
df5d108+dirty 527.06 ms 603.58 ms 76.52 ms
04207c4+dirty 459.19 ms 518.54 ms 59.35 ms
a50b33d+dirty 500.81 ms 532.11 ms 31.30 ms
5c1e987+dirty 423.52 ms 471.64 ms 48.12 ms

App size

Revision Plain With Sentry Diff
3ce5254+dirty 43.75 MiB 48.12 MiB 4.37 MiB
4953e94+dirty 43.75 MiB 48.08 MiB 4.33 MiB
2c735cc+dirty 43.75 MiB 48.08 MiB 4.33 MiB
3817909+dirty 43.75 MiB 48.08 MiB 4.33 MiB
df5d108+dirty 43.75 MiB 48.08 MiB 4.33 MiB
04207c4+dirty 43.75 MiB 48.12 MiB 4.37 MiB
a50b33d+dirty 43.75 MiB 48.08 MiB 4.33 MiB
5c1e987+dirty 43.75 MiB 48.08 MiB 4.33 MiB

Comment on lines +119 to +120
const { Linking: rnLinking } = require('react-native') as { Linking: RNLinking };
return rnLinking ?? null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Managed to overcome the persisting build issue locally with this change 🤞

Suggested change
const { Linking: rnLinking } = require('react-native') as { Linking: RNLinking };
return rnLinking ?? null;
return (require('react-native') as { Linking: RNLinking }).Linking ?? null;

Copy link
Copy Markdown
Contributor

@antonis antonis left a comment

Choose a reason for hiding this comment

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

Left a suggestion that would hopefully fix the build issue (without creating other issues) 🤞
Other than that the PR looks good overall

…icate declaration

Replace destructured import with direct property access on require result
as suggested by @antonis to fix the persisting Babel/Metro build error.
Copy link
Copy Markdown
Contributor

@antonis antonis left a comment

Choose a reason for hiding this comment

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

LGTM 🚀
Let's wait for the non flaky tests to go 🟢 before merging

@alwx alwx merged commit 7ac3378 into main Apr 14, 2026
87 of 89 checks passed
@alwx alwx deleted the alwx/improvement/deeplink-5424 branch April 14, 2026 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ExpoRouter] Investigate deep linking improvements

2 participants