Session Replay for Single-Page Applications (SPA) — What Breaks and How to Fix It
Why traditional analytics break on single-page applications and how session replay, heatmaps, and funnels handle client-side routing in React, Vue, Angular, and Svelte.
Single-page applications load once and then update the page with JavaScript. Users experience dozens of "pages," but traditional analytics may record one pageview—or count things inconsistently. Modals, drawers, tabs, and wizards that never change the URL are invisible entirely.
Session replay doesn't care how the page changes. It records what the user saw.
Table of Contents
- Why SPAs Break Traditional Analytics
- How Replay Handles SPAs
- Heatmaps on Dynamic Views
- Funnels Without Unique URLs
- Framework Setup
- Common SPA Issues Replay Reveals
- Key Takeaways
Why SPAs Break Traditional Analytics
| Problem | Effect |
|---|---|
| No full page loads | Pageviews undercounted unless routing is hooked |
| State without URLs | Modals and steps invisible |
| Async loading | "Time on page" meaningless |
| Silent JS failures | A broken view shows nothing in analytics |
How Replay Handles SPAs
DeepSync records a DOM snapshot and every mutation after it, so every view, modal, and state appears in replay. It also hooks the History API, so client-side route changes show as page views in the session timeline, heatmaps, and funnels.
Heatmaps on Dynamic Views
Heatmaps on SPAs need care:
- Group dynamic routes (e.g., /projects/123 and /projects/456) when analyzing a template.
- Watch for hidden states—clicks on a modal overlay land on the same URL as the page underneath.
- Segment by device, as SPA layouts often change a lot on mobile.
Funnels Without Unique URLs
When steps don't change the URL (a multi-step modal, an in-page wizard), use custom events:
deepsync("track", "wizard_step_completed", { step: 2 });Then build funnel steps on those events. See goals and conversions.
Framework Setup
Common SPA Issues Replay Reveals
- Infinite spinners — a request failed and the UI never handled it.
- Back button breaks — users press back and lose their progress.
- Stale state — a list doesn't refresh after an edit.
- Double submits — no disabled state on buttons.
- Route errors — a blank screen after a deploy because of a chunk load failure.
Check JavaScript errors ranked by affected sessions to find these quickly.
Chunk load errors after deploys
If users with an old tab open navigate after a deploy, lazy-loaded chunks may 404. Replay plus JS errors makes this obvious; a reload-on-chunk-error handler fixes it.
Key Takeaways
- SPAs break pageview-based analytics.
- Replay records every view and state, regardless of URL.
- Use custom events for steps that don't change the URL.
- Replay plus JS errors finds SPA-specific bugs fast.
Conclusion
Your SPA is a rich, stateful product. Your analytics should see it that way.
Frequently Asked Questions
Related articles
Stay in the loop
Get the latest insights on product analytics and user behavior delivered to your inbox.



