Skip to content
GDPR compliant. Hosted in DE.
14-day free trial →
AnalyticsBrowsersMeasurement
Analytics 14 min read 19 Sept 2026

unload Is Going Away: Keep Analytics Data Complete

Chrome is switching off the unload event in stages. How to capture dwell time, scroll depth and cart abandonment completely again by measuring on the visibility change.

X

XICTRAQ

XICTRAQ

AnalyticsBrowserMeasurement errorsPerformance
100 %
of Chrome page loads are scheduled for the switch-off from milestone 154 on 22 September 2026 (Chrome for Developers)
28 %
of desktop pages among the top 1,000 websites carry an unload handler (Web Almanac 2025)
1 in 10
desktop navigations are a back or a forward (web.dev)
Rollout of the unload switch-off in ChromeShare of page loads per milestone, status 29 June 2026Page loads without the unload eventall page loads1%M14610 Mar5%M1477 Apr10%M1485 May20%M1492 Jun40%M15030 Jun60%M15128 Jul80%M15225 Aug100%M15422 SepTriggers for the session endvisibilitychangerecommendedpagehidecache-compatibleunloadbeing switched offBack/forward cachePage with unload handlernot eligiblePage without unload handlereligible, back without reload1 in 10 desktop navigations is a backor a forward (web.dev)Sources: Chrome for Developers, web.dev
Most counting scripts attach their last data point to an event that Chrome is currently switching off. unload fired when a document was being unloaded and therefore became, over two decades, the default place for everything that still had to leave at the end of a session: dwell time, scroll depth, the cart that went unordered. Since March 2026, Chrome has been making sure that this trigger simply no longer fires for a growing share of page loads, until milestone 154 on 22 September 2026 covers all page loads (Chrome for Developers). Anyone who changes nothing gets no error, no empty response and no log entry for it, but metrics that slowly and quietly become incomplete.

What Chrome switches off by 22 September

Chrome is not disabling unload on a single cut-off date but along a ramp. The rollout to all origins has been running since 2026 across eight milestones and therefore across roughly 32 weeks (Chrome for Developers). It starts with one per cent of page loads in milestone 146 on 10 March 2026 and rises through 5, 10, 20, 40, 60 and 80 per cent to 100 per cent in milestone 154 on 22 September 2026 (Chrome for Developers). Milestone 153 is absent from the published table. The schedule carries the status of 29 June 2026 and may shift while the team monitors the impact of the rollout.

Before that, the switch-off ran for about a year as a field trial on other people's sites. In milestone 135 on 26 March 2025 it affected exactly one address; in milestone 142 on 22 October 2025 it covered the fifty most visited sites (Chrome for Developers). More important than those figures is the way of counting: the rollout is based on page loads rather than individual users or sites, so that individual users and operators are not affected more than others (Chrome for Developers). Your domain is therefore not switched over as a whole. A growing share of your visitors sits in a Chrome that no longer fires unload for this page, while the rest keeps delivering data.

A partial outage looks like a trend

Because the rollout counts page loads rather than domains, your unload beacons do not disappear at once, they become proportionally fewer. On a chart that looks like falling dwell time or fading scroll depth. Anyone unaware of the cause answers a measurement problem with a content measure. How to separate a genuine attention curve from a measurement artefact is covered in the article on scroll depth instead of bounce rate.

Why unload was already unreliable

The switch-off takes less from you than it first appears, because the promise was thin to begin with. On mobile devices unload often does not run at all: the user switches apps, the operating system pushes the tab into the background and terminates it later without asking (Chrome for Developers). The document is then discarded rather than unloaded, and an event for unloading consequently does not occur. On the desktop, unload is reasonably reliable in Chrome and Firefox, but it costs load time there because it prevents the use of the back/forward cache (Chrome for Developers).

The effect has hardly been noticed so far because it produces no error message. An event that does not fire leaves no status code in the access log, no entry in the error console and no spike in monitoring. All that is missing is one row in the database. A missing row, however, looks in every report exactly like a visitor who left sooner, and is therefore read as behaviour rather than as an outage.

  • Desktop with classic navigation: unload usually runs, but it blocks the back/forward cache. The last data point is paid for with a slower back step for every visitor.
  • Mobile browsers: tabs are pushed into the background and terminated later. The closing value often does not come into existence there, independently of the rollout.
  • Return from the cache: a restored page has not passed through unload and, in many scripts, does not count as a new page view either. The session continues, the measurement stands still.

The second loss: the back/forward cache

The back/forward cache keeps a page you have left fully in memory so that back and forward work without a new load. That is no edge case: according to Chrome usage data, one in ten navigations on desktop and one in five on mobile is either a back or a forward (web.dev). A registered unload handler makes the page ineligible for this cache. It is not stored, and every back step again costs a complete build-up including network traffic.

Since Chrome exposes the reason through the notRestoredReasons entry, this can be measured rather than guessed: the entry names the registered handler, shown in the Chrome team's example as unload-listener. Do not pin your check to that wording, because the Chrome team explicitly notes that reasons are renamed, added and removed; in Chrome 123 the same reason appears as unload-handler (Chrome for Developers). The same list often carries further blockers, above all the response header Cache-Control with the value no-store, which 23 per cent of sites now set, up from 21 per cent in 2024 (Web Almanac 2025). Anyone who removes the unload handler but leaves the header in place as a rule does not gain the cache and has done only half the work.

Two losses from one line

A single unload line costs twice over: the closing value, because the event increasingly fails to fire, and load time on the back step, because the page is not allowed into the cache. Both only become visible in cookieless reach measurement once navigation type and session end are captured separately.

How widespread the problem actually is

Prevalence depends heavily on where you count. Among the thousand most visited websites, 28 per cent of desktop pages and 20 per cent of mobile pages carry an unload handler; measured across all websites it is 11 per cent on desktop and 10 per cent on mobile (Web Almanac 2025). The share therefore rises with the size of the site. Where counting scripts, consent layers and personalisation sit on top of one another, the handler typically hides in a library that nobody deliberately added any more.

Chrome telemetry measures the same thing from a different angle and arrives at markedly smaller values, because it counts page loads rather than pages: on 4 September 2026, 0.089 per cent of measured page loads registered an unload handler, and it was fired on 0.044 per cent (Chrome Platform Status). Roughly half of the registered handlers therefore did not fire at all. How much of your traffic is affected is ultimately decided by your browser mix: in Germany, Chrome stood at just over 61 per cent in August 2026 (Statcounter).

TriggerFires onBack/forward cacheSuitability as session end
unloadunloading the document, on mobile often not at allblocks storagegoes away with the rollout
beforeunloadbefore leaving, with a possible prompt to the uservaries between browsersonly for unsaved input
pagehideleaving, reloading, closing the tabcompatiblecomplement to the main path
visibilitychange to hiddentab switch, minimise, app switch, leavingcompatiblerecommended main path

Which metrics tip first

The loss does not hit all figures equally. What is affected is everything that is only settled at the end of a page view, and those happen to be the very metrics used to judge content and the purchase path. A page view is counted on load and therefore stays complete. Dwell time, by contrast, only comes into existence on leaving and falls away without replacement when the trigger does not fire.

Dwell time and reading time

Without a closing signal, time measurement ends at the last regular sign of life. Sessions appear shorter without anything having changed in visitor behaviour.

Scroll depth

The deepest position reached is typically only sent at the very end. If that send is missing, the distribution shifts upwards and content further down appears unread.

Cart abandonment

Someone closing the tab with a full cart produces exactly one event, and it comes at the end. Without that event the abandonment is missing from the purchase path, while the purchase is still counted.

Form abandonment

Abandonment in multi-step forms is often reported on leaving. Without the last beacon, an abandoned form looks like a form that was not started at all.

The effect is one-sided: no wrong data is added, real data is missing. That is why the averages move in one direction, namely shorter dwell time, flatter scroll depth and fewer abandonments with purchases staying the same. In our experience exactly this mixture is read as a success, although it is a measurement outage. Comparing it with a second, independently collected figure separates the two cleanly: if the number of page views stays stable while the number of reported session ends falls, the trigger is to blame and not the audience.

The replacement path: measure on the visibility change

The recommended replacement is not a direct swap but a different moment. Transitioning to the hidden state is the last event a page can reliably observe and therefore the right place for the session end (MDN Web Docs). pagehide complements this path for the cases in which the document really is left and, unlike unload, is compatible with the back/forward cache (MDN Web Docs). In browsers without support for the visibility change it is the fallback path.

For the sending itself there is no way past an interface that survives the request. navigator.sendBeacon queues the data in the browser, and that queue is worked off even after unloading; the total size of the queued data is limited to 64 KiB (MDN Web Docs). Anyone who regularly wants to send more does not have a transport problem but a data model problem: at the session end, condensed metrics belong in the payload, not the complete history.

session-end.js
// One session end, two triggers, exactly one send.
let sessionEndSent = false;

function sendSessionEnd() {
  if (sessionEndSent) return;
  sessionEndSent = true;

  const payload = JSON.stringify({
    type: 'session_end',
    visible_ms: visibleTimeMs(),
    scroll_depth: maxScrollPercent(),
    path: location.pathname
  });

  // The beacon survives unloading, limit 64 KiB of total data.
  if (!navigator.sendBeacon('/a/p', payload)) {
    fetch('/a/p', { method: 'POST', body: payload, keepalive: true });
  }
}

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') sendSessionEnd();
});

// Complement for the actual unloading of the document.
window.addEventListener('pagehide', sendSessionEnd);

Two details decide the quality of this changeover. First, the send has to happen exactly once, because the hidden state can occur several times within one session; a tab switch there and back is the normal case and not a session end. Second, that change must not count as a conclusion in reporting as long as the page comes back, otherwise one session falls apart into several short ones. A flag in memory and a reset on return solve both, but they cost exactly the care that an unload one-liner used to save.

Counting restores from the cache

As soon as the unload handler is gone, your page becomes eligible for the back/forward cache, and with that a second figure changes. Because a restore brings back an existing page instead of initiating a new page load, the total number of page loads collected decreases once the cache takes effect (web.dev). That is not a deterioration but a more honest count. It does, however, break every time series that previously consisted, quietly, of reloads.

restore.js
window.addEventListener('pageshow', (event) => {
  if (!event.persisted) return;

  // The page came back from the back/forward cache: new session phase.
  sessionEndSent = false;
  resetCounters();
  send({ type: 'pageview', navigation: 'back_forward_cache' });
});

// Send the navigation type along on the first build-up.
const entry = performance.getEntriesByType('navigation')[0];
send({ type: 'pageview', navigation: entry ? entry.type : 'navigate' });

With the navigation type sent along, the time series stays explainable: navigate, reload and back_forward can be evaluated separately, and a drop in reloads with an unchanged total then becomes visible rather than puzzling. Anyone skipping this step measures a dip in traffic after the changeover that does not exist. The same pattern appears with pages preloaded via speculation rules, there with the opposite sign: additional page views that nobody has seen.

Checking what your site registers today

Every changeover starts with an inventory. Your own code base is searched quickly; the real work lies with embedded third-party scripts that bring the handler along without it ever appearing in the repository. Three measurements are enough for a solid picture: a search in the source, a search in the files actually delivered and a look at the response headers of the live address.

$ rg -n "addEventListener\(\s*['\"]unload" src/ static/
static/js/counter.js:214: window.addEventListener('unload', sendClosing);
$ rg -c "onunload|window\.onunload" static/js/*.js
static/js/counter.js:1
$ curl -sI https://your-site.example/ | rg -i 'permissions-policy'
permissions-policy: unload=()

Anyone who wants to steer the changeover instead of waiting for the rollout sets the response header Permissions-Policy with the value unload=() and switches the event off for their own origin immediately (Chrome for Developers). That is the more honest route, because the outage then shows up in testing rather than proportionally in production. For organisations with a longer lead time there is additionally an enterprise policy that preserves the old behaviour for a while; it moves the date, it does not replace the work. Interventions like these belong in a test window that fits the two-week cadence of Chrome releases.

A plan for the coming weeks

  1. Take inventory: search your own scripts, counting scripts and embedded third-party scripts for unload and onunload. Note which data point hangs on which trigger, per metric rather than per file.
  2. Set up a second measurement: measure in parallel for a week, that is, send session ends via the visibility change in addition to the existing path. Only the difference shows how much is already missing today.
  3. Switch over and remove: put the new path live and delete the unload handler. A handler left in place only for emergencies still blocks the back/forward cache.
  4. Capture the navigation type: count restores from the cache as their own category, so that the drop in reloads stays explainable and is not reported as a loss of reach.
  5. Document the break: mark the date of the changeover in your reporting. A time series without a marker is read as a trend in the next quarterly report, not as a change of method.
  6. Keep watching third-party scripts: search again after every update of embedded scripts. In our experience a removed handler comes back with the next version of a library, not with a line of your own.

A trigger that fires only on the desktop and only on an orderly exit does not deliver a complete measurement. It merely spreads the gap evenly enough that it looked like a reading for years.

— XICTRAQ

Capturing session ends reliably

The changeover is manageable as long as it is planned, and expensive once it shows up in the quarterly report. Our cookieless reach measurement sends session ends via the visibility change, counts pages restored from the back/forward cache as their own navigation type and manages this without access to device storage. For embedded third-party scripts, script integrity monitoring shows when a file has changed, and with it the moment at which a removed handler can come back. Which reports are included and to what extent is set out in the pricing overview.

Two further measuring points belong in the same round. Anyone measuring behind a proxy or a load balancer needs the correct visitor IP from X-Forwarded-For, otherwise the attribution shifts on top of the missing session end. And anyone retaining behavioural data should know what of it has to be handed out in response to an access request under Article 15; this question grows with every additional event field sent along at the session end.

Sources and surveys

Chrome for Developers on deprecating unload (timeline, status 29 June 2026), Web Almanac 2025, Performance chapter (prevalence of unload handlers and no-store), web.dev on the back/forward cache (share of back and forward navigations), MDN Web Docs on the visibility change and MDN Web Docs on sendBeacon (replacement path and queue limit), Chrome Platform Status (share of page loads with a registered handler, retrieved on 4 September 2026), Statcounter Global Stats (browser share in Germany, August 2026).

From when does unload stop firing in Chrome altogether?
The rollout runs in stages across eight milestones, starting with one per cent of page loads in milestone 146 on 10 March 2026; milestone 154 on 22 September 2026 is scheduled at 100 per cent of page loads (Chrome for Developers). The published schedule carries the status of 29 June 2026 and may shift while the impact is being monitored. Until then, mixed operation is the rule: some of your visitors still deliver the old trigger, a growing share no longer does.
Is it enough to simply replace unload with beforeunload?
As a rule, no. beforeunload is intended for unsaved input and can trigger a prompt to the user; as a measuring point it remains tied to the same condition as unload, namely an orderly exit from the document. The recommended route runs via the transition to the hidden state, because that is the last moment the page can reliably observe (MDN Web Docs), complemented by pagehide for the actual unloading.
Do I lose data by switching to the visibility change?
In our experience you gain some, because on mobile devices sessions are captured that unload would not have reached (Chrome for Developers). Two things do change nonetheless: the moment of sending moves forward, and the same event can occur several times within one session. Without a flag against duplicate sends you count every tab switch as a session end.
Why are my page views falling after I removed the unload handler?
Because the page thereby becomes eligible for the back/forward cache. A restore brings back the existing page and initiates no new page load, so the total number of page loads collected decreases once the cache takes effect (web.dev). Anyone sending the navigation type along sees the shift for what it is, instead of reporting it as a loss of reach.
How do I find unload handlers in scripts I do not write myself?
Reliably via three routes at once: a text search in the files actually delivered, the notRestoredReasons entry in the browser, which reports the handler as a reason (spelled unload-listener or unload-handler depending on the version, which is why the Chrome team advises against relying on the wording), and monitoring of file changes in embedded third-party scripts. The third point is the most important, because a handler removed once typically returns with the next update of the library.
Does this only affect Chrome?
The schedule described is Chrome's, and in Germany Chrome stood at a usage share of just over 61 per cent in August 2026 (Statcounter). In practice, however, the question is broader: on mobile devices and in browsers that give priority to the back/forward cache, unload often failed to fire even before (Chrome for Developers). A measuring path without this event is therefore the more robust basis regardless of the rollout.
Start in 60 seconds

Let XICTRAQ watch your website.

Permanent free plan available. No credit card, no installation, no hidden fees.