The Back Button Problem — Why Users Get Lost in Single-Page Apps
When the back button closes the whole flow, loses a filled form, or resets scroll position, visitors leave. Learn the common back-button failures in single-page apps, how they appear in session recordings, and how to fix history, scroll, and state.
Short answer: users expect the back button to undo their last navigation: close the modal, return to the previous step, or go back to the list at the position they left. In a single-page app this only works if the app records each meaningful view in the browser's history and restores state and scroll on return. When it does not, back exits the flow or the site. On Android, where the system back gesture is the main way to go back, this is one of the most common causes of accidental abandonment.
Table of Contents
What Users Expect
The back button is among the most used controls on the web. People use it without thinking, and they trust it. On Android phones the back gesture works in every app, and users apply it to websites the same way.
Their mental model is simple: back takes me to what I was looking at before.
Common Failures
| Failure | What the user experiences |
|---|---|
| Modal or full-screen overlay not in history | Back closes the whole page instead of the overlay |
| Multi-step form as one URL | Back from step three leaves the form, losing everything |
| Filters and sort not in the URL | Back from a product returns to an unfiltered list (filters) |
| Scroll position not restored | Back returns to the top of a long list |
| Infinite scroll content not restored | Back returns to the first page of results |
| Tabs not in history | Back leaves the page instead of the previous tab |
| Redirect loops | Back lands on a page that immediately forwards again |
| History filled with trivial entries | Back must be pressed many times to leave |
| Back hijacked to show a popup | The user is trapped; trust is lost |
| Form data lost on return | Fields are empty after coming back |
| Payment redirect return | Back from a payment page shows an expired or broken state |
The product list case is the most costly in commerce. A shopper scrolls sixty products deep, opens one, presses back, and is at the top. Few scroll down again (product listing pages).
How It Appears in Recordings
Back-button problems leave a distinctive trace in session replay.
| What you see | Meaning |
|---|---|
| Session ends abruptly from inside a modal or step | Back exited the site |
| User returns to a list at the top, scrolls a little, leaves | Scroll position lost |
| Filters reapplied after returning from a product | Filter state lost |
| A form's first step shown again, fields empty, then exit | Progress lost |
| The same page loaded twice in quick succession | A redirect bounce |
| Exit from a lightbox image view | Back closed the page, not the image (image galleries) |
| A user leaves, and returns seconds later to the same URL | They pressed back by reflex and came back to retry |
That last pattern, exit and immediate re-entry, is a useful search. The visitor did not want to leave.
Session replay needs to follow route changes without page loads to show this properly. DeepSync records single-page apps as one continuous session and tracks route changes as page views (replay for SPAs).
Fixes
1. Give every meaningful view a history entry.
Opening a full-screen overlay, moving to the next step, or switching a major tab should push a state. Then back reverses it. Small changes, such as expanding an accordion, should not.
// Opening a full-screen filter panel
history.pushState({ panel: "filters" }, "", "?panel=filters");
window.addEventListener("popstate", (event) => {
if (!event.state || event.state.panel !== "filters") closeFilterPanel();
});Most routing libraries handle this if you model the overlay or step as a route or a search parameter.
2. Put state in the URL.
Filters, sort order, search query, page number, and the selected tab belong in the URL. This makes back work, and also makes the view shareable and reloadable.
Use replaceState for refinements within the same view, such as typing in a search box, so history is not flooded. Use pushState for a new view.
3. Restore scroll.
Browsers restore scroll for normal pages. In a single-page app the content may not exist yet when the browser tries. Store the scroll position when leaving a list and restore it after the list has rendered. Most frameworks offer a scroll restoration option. Test it with real data and slow loading.
For infinite scroll, restore the loaded items too, or use paginated URLs so the position can be rebuilt.
4. Keep form data.
Hold form state outside the component that is unmounted, or in session storage, so returning to a step shows what was entered. Do not store sensitive values such as card numbers.
5. Handle payment returns.
After a redirect to a payment provider, pressing back should show a clear state: "Your payment is being processed" or "Payment was not completed, try again". Not an expired page or a duplicate charge (UPI and payment drop-off).
6. Never hijack back.
Intercepting the back button to show an exit offer or block leaving is a dark pattern. It breaks a control people rely on (popups and exit intent).
7. Warn only where work would be lost.
A confirmation before leaving a long unsaved form is reasonable. Saving the draft automatically is better.
8. Test on Android with the back gesture.
Go through every flow, pressing back at each step. Include modals, galleries, filters, and the checkout.
Measuring It
- Find exits from mid-flow states. Sessions that end on a step or overlay that has no natural reason to be an exit (exit pages).
- Send an event when a critical overlay or step is open, so sessions ending there can be filtered:
deepsync("track", "filter_panel_opened");- Compare mobile and desktop exit rates for the same step. Back-gesture exits are concentrated on Android.
- Watch the sessions. The abrupt end, with no hesitation before it, distinguishes an accidental exit from a decision to leave.
- After fixing, compare that step's completion on mobile.
Press back at every step of your own checkout
On an Android phone, use the back gesture at each stage, including inside every popup. Wherever you fall out of the flow, your customers do too.
Key Takeaways
- Users expect back to undo their last navigation.
- Record meaningful views in history; keep state in the URL.
- Restore scroll and form data on return.
- Look for abrupt mid-flow exits on Android in recordings.
Conclusion
The back button is a promise the browser made to your visitors long before they reached your site. A single-page app has to keep it on the browser's behalf.
Frequently Asked Questions
Related articles
Stay in the loop
Get the latest insights on product analytics and user behavior delivered to your inbox.



