Suggest an editImprove this articleRefine the answer for “The unload event”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`unload` fires at the moment the document is already being unloaded from the browser's memory: the user closed the tab, pressed F5, followed a link or navigated to another page with a full reload.** You cannot cancel the navigation from this handler, and you cannot show a dialog either; the browser does not wait for asynchronous work, so `fetch` and `setTimeout` will not finish here. Only synchronous actions (writing to `localStorage`) or `navigator.sendBeacon()` are usable. In Safari and on iOS `unload` is often not fired at all, so the more reliable modern replacement is `pagehide`. ```javascript window.addEventListener('unload', () => { navigator.sendBeacon('/analytics', JSON.stringify({ event: 'exit' })); }); ``` **Key point:** `beforeunload` means "warn before leaving", `unload` means "clean up after leaving".Shown above the full answer for quick recall.Answer (EN)Image**`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 - `unload` fires 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 `unload` handler; that is what `beforeunload` is 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`, plus `navigator.sendBeacon()`. - In some browsers (Safari, iOS) `unload` may not fire at all; the modern replacement is `pagehide`. - Typical jobs: logging the exit, saving state, closing WebSocket connections. ### Quick example ```javascript 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: ```javascript 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`, or `navigator.sendBeacon()`. - In some browsers (Safari, iOS) `unload` **is not fired at all**, they use `pagehide` instead. 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: ```javascript 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. ```javascript 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:** > `beforeunload` means "warn before leaving", > `unload` means "clean up after leaving". ### Common mistakes - **Calling `fetch` in `unload`.** The browser aborts the request together with the page; use `navigator.sendBeacon()`. - **Counting on `setTimeout` or 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 of `beforeunload`. - **Relying on `unload` in mobile Safari.** The event may never fire and the state is lost; listen to `pagehide` or `visibilitychange`. - **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.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.