Allow the session replay recorder to customize/normalize the recorded URL (or run in manual mode)
Problem
The tracker (script.js) lets an app control the URL it reports: with data-auto-track="false" (or data-auto-pageview="false") plus umami.track(props => ({ ...props, url })), a single-page app can send a normalized route instead of the raw location.href.
The recorder (recorder.js) has no equivalent. Inspecting the current bundle, it only reads two attributes:
data-website-iddata-host-url
Why it matters
For SPAs with dynamic route parameters (e.g. /foo/HM547WwgG), the app already normalizes pageview URLs to /foo/:id, but the recorder bypasses that layer and stores the raw path. Two consequences:
- Heatmaps fragment. Each distinct parameter becomes its own "page" in the Pages list, so clicks never aggregate into a meaningful heatmap.
- Sensitive identifiers get recorded. In privacy-sensitive apps, the raw path itself is sensitive data, and there is currently no way to keep it out of replay/heatmap storage even though the rest of the analytics pipeline already strips it.
maskLevel: strict does not help here — it masks text and inputs, not the URL.
Proposed options (any one would solve it)
- A
data-before-send-style hook on the recorder that receives the URL (and optionally the event) and can transform or drop it, mirroring the tracker. - Have the recorder reuse the tracker's already-normalized URL / session context instead of reading
location.hrefindependently. - A
data-*attribute to point the recorder at a user-provided URL transform function onwindow.
Option 2 would be the most consistent, since it would make replay/heatmap URLs match what the tracker already reports.
Environment
- Umami self-hosted v3.3.0
- SPA (Angular) with manual pageview tracking (
data-auto-track="false")
Source: umami-software/umami