The unload event
unload is an event that fires when the document is being unloaded from the browser's memory. It runs at the very last moment of the page's life, when the navigation can no longer be stopped and all you can do is clean up quickly.
Theory
TL;DR
unloadfires when the user closes the tab, reloads the page (F5), follows a link, or navigates to another page with a full reload.- You cannot stop the navigation or show a dialog from an
unloadhandler; that is whatbeforeunloadis for. - Asynchronous work (
fetch,setTimeout) does not get a chance to finish: the browser does not wait for it. - Only synchronous actions work, for example writing to
localStorage, plusnavigator.sendBeacon(). - In some browsers (Safari, iOS)
unloadmay not fire at all; the modern replacement ispagehide. - Typical jobs: logging the exit, saving state, closing WebSocket connections.
Quick example
window.addEventListener('unload', () => {
// runs at the very last moment, when the page is already leaving memory
console.log('The page is unloading...');
});When unload fires
The event happens when the document leaves the browser's memory. In practice that means the user:
- closes the tab;
- reloads the page (
F5); - follows another link;
- or moves to another page in an SPA with a full reload.
Typical use cases:
- sending statistics or logs "before the user leaves";
- saving data to
localStorage/sessionStorage; - closing connections, WebSockets, releasing resources.
For example, storing the time of the last visit:
window.addEventListener('unload', () => {
localStorage.setItem('lastVisited', new Date().toISOString());
});unload is not beforeunload
The two events are easy to confuse, but they solve different problems: beforeunload fires before the unload and can still stop it, while unload fires during the unload, when it is already too late to decide anything.
| Property | beforeunload | unload |
|---|---|---|
| When it fires | Before unloading | During unloading |
| Can the exit be stopped | Yes (preventDefault()) | No |
| Can a warning be shown | Yes | No |
| Can code be executed | Yes, but with limits | Very limited |
| Typical jobs | Warn about unsaved data | Cleanup, logging |
Limits and caveats
Modern browsers restrict unload heavily so that closing pages is not slowed down:
- Asynchronous actions (
fetch,setTimeout) do not work, the browser does not wait for them to complete. - You cannot show a dialog or a modal window.
- Only synchronous operations work, for example writing to
localStorage, ornavigator.sendBeacon(). - In some browsers (Safari, iOS)
unloadis not fired at all, they usepagehideinstead.
One more downside: merely having an unload handler (same for beforeunload) makes the page ineligible for the bfcache, the back/forward cache, so returning to it becomes slower.
The recommended alternative: pagehide
pagehide is a more modern and more reliable event, especially in mobile browsers:
window.addEventListener('pagehide', (event) => {
// event.persisted === true means the page is going into the bfcache
console.log('The page was hidden or unloaded');
});It works even when the user switches to another tab and fires more reliably than unload. For analytics people often add visibilitychange with the hidden state as well, because on mobile that is the only moment guaranteed to happen.
Sending analytics when the page closes
The only safe way to send data to the server at closing time is navigator.sendBeacon(): the request is queued by the browser and delivered even after the page is gone.
window.addEventListener('unload', () => {
navigator.sendBeacon('/analytics', JSON.stringify({ event: 'exit' }));
});Formally the call is asynchronous, but the browser takes delivery upon itself, so the data is not lost the way it would be with a plain fetch.
A summary of the event:
| What it does | The unload event |
|---|---|
| When it fires | When the user leaves the page |
| Can the navigation be stopped | No |
| Good for | Cleanup, logs, saving state |
| Does it work asynchronously | No (synchronous only, or via sendBeacon) |
| Modern alternative | pagehide |
| Common use | Analytics, saving state |
An easy way to remember:
beforeunloadmeans "warn before leaving",unloadmeans "clean up after leaving".
Common mistakes
- Calling
fetchinunload. The browser aborts the request together with the page; usenavigator.sendBeacon(). - Counting on
setTimeoutor promises. Micro- and macrotasks will not run any more, the document is leaving memory. - Trying to cancel the navigation in
unload.preventDefault()has no effect here, that is the job ofbeforeunload. - Relying on
unloadin mobile Safari. The event may never fire and the state is lost; listen topagehideorvisibilitychange. - Forgetting that the handler breaks the bfcache. The page stops being cached, so going "back" becomes slower.
- Doing heavy work in the handler. Long synchronous code visibly delays closing the tab for the user.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.