The HTML5 History API lets a client-side app change the address-bar URL and session history without immediately loading a new document. Use pushState() to create a Back-button stop, replaceState() to amend the current stop, and popstate to update your app when Back or Forward activates another entry.
What the History API changes—and what it does not
The browser exposes the current tab’s session history through window.history. Its traversal methods are back(), forward(), and go(); its entry-modification methods are pushState() and replaceState(). The WHATWG HTML Standard defines pushState() as adding an entry with serialized state and a URL.
When you call either state method with a URL, the address bar and history metadata can change, but the browser does not fetch that URL or render a new page for you. Your application must render the view itself. This distinction is central to client-side routing: the URL describes the route, while application code keeps the displayed interface in sync. See MDN’s guide to working with the History API.
Choose pushState or replaceState by the Back-button result
| Method | Effect on session history | Use it when |
|---|---|---|
history.pushState(state, "", url) |
Adds a new entry; Back can return to the previous entry. | The user has moved to a distinct view that should be a separate Back-button step, such as opening a product detail or moving to another route. |
history.replaceState(state, "", url) |
Updates the active entry without adding a Back-button step. | You are correcting or initializing the current route, or updating its associated state without treating it as a new navigation. |
The second parameter is retained for historical reasons; an empty string is conventional. The URL parameter is optional. When provided, it must be same-origin with the current document. Refer to MDN’s pushState() reference for parameter and exception details.
#1 Best Overall
Put routes in the URL and entry-specific data in state
Use the URL for route information that should be shareable, bookmarkable, or recoverable after a reload. The state object is associated with a history entry and is opaque to the browser; it can hold compact, serializable data the application needs when returning to that entry. Avoid putting secrets in URLs: a URL changed through this API may be sent as the Referer on later requests.
State must be serializable. Browsers may limit its size, so avoid storing large page data in history state; MDN suggests sessionStorage or localStorage when more storage is needed. Keep in mind that storage and history state serve different purposes: history state is tied to an entry, while web storage is not a substitute for choosing a URL that can be requested directly.
Rank #2
Implement navigation and Back/Forward synchronization
Render the new view as part of your own navigation flow. Calling pushState() does not fire popstate, so do not rely on that event to render the view immediately after a new in-app navigation. Listen for popstate to update the interface when browser traversal activates another history entry.
function navigate(path, viewState) {
history.pushState(viewState, "", path);
renderRoute(path, viewState);
}
window.addEventListener("popstate", (event) => {
renderRoute(window.location.pathname, event.state);
});
In this pattern, renderRoute() is application code that you provide. Adapt it to your router and URL scheme; for example, it may need to consider the query string or hash as well as pathname. The key is to render directly after your app initiates navigation and to render again when popstate reports a traversal. MDN’s History API guide covers this single-page-app use case.
Make every exposed route work on direct requests
A route added with pushState() is not checked or loaded when it is added. But a user may reload the page, bookmark the address, or open it directly. Configure the application’s server or hosting layer to serve the app for valid client-side routes, and make the application render the correct view from the requested URL. Otherwise, in-app navigation can appear to work while reloads and shared links fail.
Know which events do and do not fire
popstateis for history traversal activating an entry; it does not fire just because your code calledpushState().pushState()does not firehashchange, even if the new URL has a different hash.- Handle the app’s own navigation explicitly rather than waiting for browser events to report changes your code initiated.
These event details are described in MDN’s History API guide and the MDN pushState() reference.
Rank #4
Handle invalid state and URL failures
History calls can fail rather than silently accepting unsuitable data or a URL. A non-serializable state value can cause a DataCloneError. Invalid or cross-origin URLs and other disallowed conditions can cause a SecurityError. Keep state compact and pass a same-origin URL when you provide one. The applicable conditions and exceptions are documented in the WHATWG standard and MDN reference.
History API limits
Ordinary page scripts cannot erase the tab’s session history or disable the browser’s Back and Forward controls. The History API modifies and traverses entries within the browser’s rules; it is not a way to trap users in a page. See MDN’s Window.history reference.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteQuick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

