Skip to content

🐛 Resolve document-relative URLs against document.baseURI in normalizeUrl - #4943

Open
odonckers wants to merge 1 commit into
DataDog:mainfrom
odonckers:odonckers/rum-core/fix-normalize-url-base-uri
Open

🐛 Resolve document-relative URLs against document.baseURI in normalizeUrl#4943
odonckers wants to merge 1 commit into
DataDog:mainfrom
odonckers:odonckers/rum-core/fix-normalize-url-base-uri

Conversation

@odonckers

@odonckers odonckers commented Aug 12, 2026

Copy link
Copy Markdown

Motivation

Fixes #4944.

normalizeUrl resolves relative URLs against location.href, but the browser resolves relative
request URLs against the document base URI (<base href>). On any page whose path is deeper
than the base href, the URL the RUM SDK records for a fetch/XHR differs from the URL the browser
actually requested. The resulting resource event cannot be matched to its
PerformanceResourceTiming entry, so it silently loses method, status_code, _dd.trace_id
and _dd.span_id — breaking RUM → APM correlation.

This affects any app that issues document-relative request URLs (no leading /, no scheme)
from a route deeper than its base href — the default shape for SPAs served at / with a router:
<base href="/"> plus an API base of api/.

With <base href="/"> on route /deep/route, a request to api/foo gives:

URL
Actual request, and PerformanceResourceTiming.name https://host/api/foo
Recorded by normalizeUrl (base https://host/deep/route) https://host/deep/api/foo

traceparent / x-datadog-* headers are still injected (tracing usually prefix-matches on origin,
which the mis-resolved URL preserves), so the backend span looks correct — the breakage is only
visible on the RUM side, where the resource event carries no _dd.trace_id.

Changes

packages/js-core/src/util/urlPolyfill.ts — resolve against document.baseURI, falling back to
location.href where there is no document:

export function normalizeUrl(url: string) {
  return buildUrl(url, globalObject.document?.baseURI ?? globalObject.location?.href).href
}
  • Absolute and root-relative inputs are unaffected — the base argument is ignored for those, which
    is the large majority of normalizeUrl calls (view URLs, resource entry names, intake URLs).
  • Behaviour only changes for document-relative inputs, and only on pages that declare a
    <base href> differing from the current path — where the new result is what the browser
    actually requested.
  • Worker/SSR behaviour is preserved via the location.href fallback.
  • Signature is unchanged, so the @datadog/js-core public API surface is unaffected
    (api:check passes).

Test instructions

Unit tests (added in packages/browser-core/src/tools/utils/urlPolyfill.spec.ts) cover a
<base href> differing from the current path:

yarn test:unit --spec packages/browser-core/src/tools/utils/urlPolyfill.spec.ts

Manual reproduction:

  1. Serve a page at /deep/route with <base href="/"> and RUM initialised with
    allowedTracingUrls: [window.location.origin].
  2. Issue new XMLHttpRequest().open('GET', 'api/foo') / fetch('api/foo').
  3. Before this change, the request carries traceparent but the RUM resource event has no
    _dd.trace_id, _dd.span_id, method or status_code. After this change, all four are
    present and the resource event matches its PerformanceResourceTiming entry.

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

…eUrl

normalizeUrl resolved relative URLs against location.href, but the browser
resolves relative request URLs against the document base URI (<base href>). On
a route deeper than the base href, the URL recorded for a fetch/XHR differed
from the one actually requested, so the resource event never paired with its
PerformanceResourceTiming entry — dropping method, status_code, _dd.trace_id
and _dd.span_id and breaking RUM → APM correlation.

Resolve against document.baseURI, falling back to location.href where there is
no document (workers, SSR). Absolute and root-relative inputs are unaffected.
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@odonckers

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@odonckers
odonckers marked this pull request as ready for review August 12, 2026 15:30
@odonckers
odonckers requested a review from a team as a code owner August 12, 2026 15:30
@sbarrio
sbarrio requested a review from mormubis August 13, 2026 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Relative XHR/fetch resource events lose trace_id with a <base href>

1 participant