The SDK patches history.pushState / history.replaceState and listens for
popstate, so every route change — and every back/forward — becomes a crumb.
That covers Vue Router, SvelteKit, the Angular Router and Astro’s view
transitions with no configuration, because all of them navigate through the
History API.
// nothing beyond the normal init
init({ apiKey: 'evf_live_…' });
// → breadcrumb: "/cart → /checkout?step=2"
The screen name is pathname + search. Same-URL transitions are dropped, and
the patch installs once per page no matter how many times you call
init()/destroy() — it is claimed behind a marker and re-claimed by the next
init(), so it neither accumulates nor keeps capturing for a torn-down client.
The hash-routing gap
Screen names are built from pathname and search only. A router that
navigates purely in the fragment — /#/checkout — never changes the tracked URL
and emits no crumbs. This catches out hash-mode Vue Router and any router left
in its hash fallback for a static host.
Switch that route tree to History-API mode to get the trail automatically. Or keep the hash router and mark the screens yourself, from wherever you already observe route changes:
everframe.recordScreen('Checkout');
Marking screens by hand
recordScreen(name, data?) sits on the handle init() returns. It exists for
anything the URL does not describe: a hash router, a wizard whose steps share one
route, a modal stack, or a canvas app with no routes at all.
const everframe = init({ apiKey: 'evf_live_…' });
router.afterEach((to) => everframe.recordScreen(to.name));
Pass it the name only — it derives the from → to transition itself, matching
the shape the native SDKs emit, so a web timeline and a native one read
identically in one dashboard. Do not hand-build a kind: 'navigation'
breadcrumb; recordScreen applies five rules that a hand-rolled crumb misses.
How the chain behaves
- One global chain, chronological. A tab switch reads
TabA → TabB. - The first screen emits nothing. There is nothing to come from yet. It
still becomes the
fromof the next transition. A → Ais suppressed. Refocus, remount or a double-wired integration never produce a crumb.- A blank name is not a screen. The chain is left untouched, so the next real screen still reports a transition from the last real one.
fromandtoare authoritative. Your owndatakeys of those names cannot forge the transition they are attached to.
Disabling the navigation breadcrumb kind stops these crumbs and the
automatic ones together — the chain keeps tracking underneath, so re-enabling
mid-session resumes from the true previous screen rather than a stale one.
Running two clients, or wiring a recorder to your own crumb sink, is what
createScreenRecorder is for; each recorder holds its own from, so they
cannot bleed into each other.
Naming screens
Names travel in the report and are shown in triage. They do pass through the breadcrumb buffer’s redaction, so an obvious email or card number in a URL is caught — but redaction recognises shapes, not meaning, and an order id or an internal username sails through. Do not rely on it.
The name comes from the URL, which means the rule is about your routes:
prefer /orders/:id shapes over paths that embed an email or a token in the
query string. If a route genuinely carries something sensitive, mark it with
redaction rules so it is scrubbed before capture.
What lands in the envelope
Navigation crumbs are entries in payload.breadcrumbs, the same timeline that
carries taps, console, network, lifecycle and error entries:
{
"t": 1755500000000,
"seq": 42,
"kind": "navigation",
"message": "/cart → /checkout",
"data": {
"from": "/cart",
"to": "/checkout"
}
}
t is the shared epoch-millisecond clock that also stamps the session replay,
so a receiver can align a crumb to a replay frame by direct comparison.
Caps and trimming behaviour are in Errors & limits.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| No crumbs on an app that clearly changes routes | Hash-based routing, or a router that re-renders without touching the History API. |
| Crumbs stop the moment the reporter opens | Expected. The trail is frozen when the report opens so the reporter’s own UI never pollutes the evidence. |
| The same screen appears twice in a row | It should not — A → A is suppressed. If you see it, the two URLs differ in search. |
| A full page load produced no crumb | Only client-side navigation is patched. A server-rendered navigation is a new page, and the trail starts over with it. |