As a full-stack developer who's been in the trenches for over two decades (I'm old people!), I've seen browser APIs come and go. Today, I want to talk about an old friend that's on its way out: the unload
event. If you've been hanging onto this event in your codebase, it's time we had a chat about why you should say goodbye to the unload
event (in case you didn't do so already).
What's happening with the unload event?
Google Chrome is gradually phasing out the unload
event starting this month (March 2025). The rollout begins with just google.com, then expands to more top sites, and eventually reaches all websites by April 2026. This isn't a sudden change - Chrome has been telegraphing this move since 2019 when they announced their back/forward cache implementation plans.
Why I won't miss the unload event
Let's be honest - the unload
event has been more trouble than it's worth for years now. Here's why I'm happy to see it go:
It was never reliable to begin with
We've all been there. You add an unload
handler to save some critical user data, only to discover later that it didn't fire half the time on mobile devices. The reason? Mobile browsers often don't trigger unload
when tabs are backgrounded and killed by the OS. What seemed like a safety net was actually full of holes.
It kills performance optimizations
The back/forward cache (bfcache) is one of the best performance improvements browsers have implemented in recent years. It creates an instant back/forward navigation experience by freezing a page in memory. The problem? Pages with unload
handlers can't use this cache, forcing users to wait for a full page reload when navigating.
Modern browsing patterns have changed
Think about how you use browsers today compared to 15 years ago. We have dozens of tabs open across multiple windows. We leave tabs dormant for days. We switch devices mid-session. The idea that there's a clean "unload" moment when a user leaves your page is a relic of a simpler web.
The deprecation schedule
Chrome is taking it slow, which gives us time to adapt:
- March 2025: Just google.com loses
unload
support (Chrome 135) - April-June 2025: Expanding to 50 top websites (Chrome 136-138)
- August 2025-April 2026: Gradual rollout to all sites (Chrome 140-147)
Better ways to handle page exits
So what should you use instead? Here are three better options I've adopted in my own projects:
The visibilitychange event
The visibilitychange
event (part of Page Visibility API) is my go-to replacement. It fires when a user switches tabs or minimizes the browser - often the last reliable chance to save data:
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') { // Last chance to save data - the user is navigating away saveUserProgress(); // Don't count on getting more execution time after this } });
Baseline Widely available
Page visibility is well established and works across many devices and browser versions.
- Supported as of Chrome 33, Edge 12, Firefox 18 and Safari 7
- Resulting in full support since July 29, 2015
- Continue reading about page visibility
Register to RUMvision to see more resources and learn if your website visitors would already benefit from this feature today.
The pagehide event
Similar to unload
but compatible with the back/forward cache, the pagehide
event (part of PageTransitionEvent) can be used:
window.addEventListener('pagehide', (event) => { // Clean up things that would break if the page gets frozen and restored later // event.persisted tells you if the page might be restored from bfcache later if (event.persisted) { console.log('This page *might* be entering the bfcache.'); } else { console.log('This page will unload normally and be discarded.'); } });
This code can be found in the bfcache article on web.dev.
Baseline Widely available
Page transition events is well established and works across many devices and browser versions.
- Supported as of Chrome 4, Edge 12, Firefox 1.5 and Safari 5
- Resulting in full support since July 29, 2015
- Continue reading about the pagetransitionevent interface
Register to RUMvision to see more resources and learn if your website visitors would already benefit from this feature today.
Selective use of beforeunload
The beforeunload
event (which shows a browser native "Leave site?" dialog) isn't being deprecated, but you should still use it sparingly as beforeunload
is still unreliable. That's because the beforeunload
event might never be fired in some scenarios. and suggests to avoid using it unless absolutely necessary.
function updateLeaveWarning(hasUnsavedChanges) { // Only add the warning when there are unsaved changes if (hasUnsavedChanges) { window.addEventListener('beforeunload', showWarning); } else { window.removeEventListener('beforeunload', showWarning); } } function showWarning(e) { // Browsers standardize the dialog message regardless of what text we provide e.preventDefault(); return e.returnValue = 'Are you sure you want to exit?'; } // Add listeners to track changes formElement.addEventListener('change', () => { updateLeaveWarning(true); }); saveButton.addEventListener('click', () => { updateLeaveWarning(false); });
Limited availability
beforeunload is not Baseline because it does not work in some of the most widely-used browsers.
- Only supported in Chrome 1, Edge 12, Firefox 1 and Safari 3
- Continue reading about the beforeunloadevent interface
Register to RUMvision to see more resources and learn if your website visitors would already benefit from this feature today.
fetchLater API
Another promising alternative, particularly for analytics and monitoring use cases, is the fetchLater API. Coming out of origin trial phase, this (Chromium >= 135) API directly addresses one of the most common unload
event use cases.
Back in the days, performance monitoring solutions like New Relic and Dynatrace ended up using the unload
event as a means to dispatch analytics data by sending a beacon when unload
was fired. This approach created a difficult trade-off: despite being performance monitoring solutions, they were either actively impacting site performance (by blocking the back/forward cache) or having their data collection silently fail when unload
events didn't fire.
The fetchLater API solves this by allowing developers to queue network requests that will be sent even after a page is closed:
// Queue an analytics request that will be sent even if the page is closed navigator.fetchLater.fetch('https://analytics.example.com/collect', { body: JSON.stringify({event: 'page_exit', duration: pageSessionTime}), method: 'POST', keepalive: true });
Unlike the unload event, the fetchLater API approach allows the browser to optimize page transitions while still ensuring your analytics data gets sent reliably.
Limited availability
fetchLater is not Baseline because it does not work in some of the most widely-used browsers.
- Only supported in Chrome 135 and Edge 135
- Continue reading about 1647
Register to RUMvision to see more resources and learn if your website visitors would already benefit from this feature today.
Finding unload usage in your codebase
Before you can fix the problem, you need to find it. Here's how I hunt down unload
usage:
Look for direct event handlers
Search your codebase for:
addEventListener('unload'
onunload
.unload(
(for jQuery)
Check for back/forward cache eligibility
Open Chrome DevTools, navigate to Application > Background services > Back/forward cache, and click "Test back/forward cache". If your page fails the test due to an unload
handler, Chrome will tell you.
Disabling and reporting
As a site owner, you can choose to disable the use of the unload
event altogether. This will keep your site eligible for the back/forward cache, even if existing or newly added (third-party) scripts start to use the unload
handler again.
Alternatively, you can already start detecting which scripts are still actively using the unload
handler. This can be achieved by using the Reporting API and sending data to an endpoint of your choice.
This GitHub explainer document covers both scenarios.
Options while you migrate
If you need more time, Chrome offers several ways to postpone the inevitable:
For developers testing locally
Enable the Chrome flag at chrome://flags/#deprecate-unload
to simulate the future behavior now and test your fixes.
For website owners
Use the Permissions Policy header to explicitly opt-in to keep using unload
during the transition:
Permissions-Policy: unload=self
For enterprise IT
If you manage a corporate environment with legacy applications, look into the ForcePermissionPolicyUnloadDefaultEnabled
enterprise policy to delay the deprecation.
Let's face reality
The deprecation of unload
is actually a helpful reminder that we never had as much control over the web page lifecycle as we thought. Users have always been able to kill our pages without warning - by force-quitting browsers, running out of battery, or losing network connections.
Good web development means designing for resilience. Save data early and often. Use client-side storage wisely. Sync to servers when connections are available. These practices have always been better than relying on an unload
event that might never come.
So while it might be annoying to update your code now, it's pushing us toward more reliable patterns that better match how people actually use the web today. That's something we can all get behind, right?