feat(browser): Detect redirects when emitting navigation spans
Closes https://github.com/getsentry/sentry-javascript/issues/15286
This PR adds a new option to browserTracingIntegration, detectRedirects, which is enabled by default. If this is enabled, the integration will try to detect if a navigation is actually a redirect based on a simple heuristic, and in this case, will not end the ongoing pageload/navigation, but instead let it run and create a navigation.redirect zero-duration span instead.
An example trace for this would be: https://sentry-sdks.sentry.io/explore/discover/trace/95280de69dc844448d39de7458eab527/?dataset=transactions&eventId=8a1150fd1dc846e4ac8420ccf03ad0ee&field=title&field=project&field=user.display&field=timestamp&name=All%20Errors&project=4504956726345728&query=&queryDataset=transaction-like&sort=-timestamp&source=discover&statsPeriod=5m×tamp=1747646096&yAxis=count%28%29
Where the respective index route that triggered this has this code:
setTimeout(() => {
window.history.pushState({}, "", "/test-sub-page");
fetch('https://example.com')
}, 100);
The used heuristic is:
- If the ongoing pageload/navigation was started less than 300ms ago...
- ... and no click has happened in this time...
- ... then we consider the navigation a redirect
this limit was chosen somewhat arbitrarily, open for other suggestions too.
While this logic will not be 100% bullet proof, it should be reliable enough and likely better than what we have today. Users can opt-out of this logic via browserTracingIntegration({ detectRedirects: false }), if needed.
size-limit report 📦
| Path | Size | % Change | Change |
|---|---|---|---|
| @sentry/browser | 23.99 kB | - | - |
| @sentry/browser - with treeshaking flags | 23.76 kB | - | - |
| @sentry/browser (incl. Tracing) | 39.85 kB | +0.6% | +235 B 🔺 |
| @sentry/browser (incl. Tracing, Replay) | 78.06 kB | +0.31% | +238 B 🔺 |
| @sentry/browser (incl. Tracing, Replay) - with treeshaking flags | 71.09 kB | +0.27% | +187 B 🔺 |
| @sentry/browser (incl. Tracing, Replay with Canvas) | 82.77 kB | +0.28% | +225 B 🔺 |
| @sentry/browser (incl. Tracing, Replay, Feedback) | 94.99 kB | +0.3% | +277 B 🔺 |
| @sentry/browser (incl. Feedback) | 40.76 kB | - | - |
| @sentry/browser (incl. sendFeedback) | 28.7 kB | - | - |
| @sentry/browser (incl. FeedbackAsync) | 33.59 kB | - | - |
| @sentry/react | 25.76 kB | - | - |
| @sentry/react (incl. Tracing) | 41.85 kB | +0.58% | +239 B 🔺 |
| @sentry/vue | 28.37 kB | - | - |
| @sentry/vue (incl. Tracing) | 41.66 kB | +0.6% | +246 B 🔺 |
| @sentry/svelte | 24.01 kB | - | - |
| CDN Bundle | 25.5 kB | - | - |
| CDN Bundle (incl. Tracing) | 39.82 kB | +0.48% | +187 B 🔺 |
| CDN Bundle (incl. Tracing, Replay) | 75.8 kB | +0.25% | +187 B 🔺 |
| CDN Bundle (incl. Tracing, Replay, Feedback) | 81.27 kB | +0.24% | +193 B 🔺 |
| CDN Bundle - uncompressed | 74.5 kB | - | - |
| CDN Bundle (incl. Tracing) - uncompressed | 118.25 kB | +0.41% | +481 B 🔺 |
| CDN Bundle (incl. Tracing, Replay) - uncompressed | 232.55 kB | +0.21% | +481 B 🔺 |
| CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed | 245.38 kB | +0.2% | +481 B 🔺 |
| @sentry/nextjs (client) | 43.48 kB | +0.52% | +222 B 🔺 |
| @sentry/sveltekit (client) | 40.32 kB | +0.59% | +235 B 🔺 |
| @sentry/node | 161.84 kB | - | - |
| @sentry/node - without tracing | 98.79 kB | - | - |
| @sentry/aws-serverless | 124.61 kB | - | - |
:x: Unsupported file format
Upload processing failed due to unsupported file format. Please review the parser error message:
Error parsing JUnit XML in /home/runner/work/sentry-javascript/sentry-javascript/packages/solidstart/vitest.junit.xml at 18:17 Caused by: RuntimeError: Error parsing XML Caused by: 0: ill-formed document: expected `</testsuites>`, but `</testsuite>` was found 1: expected `</testsuites>`, but `</testsuite>` was foundFor more help, visit our troubleshooting guide.