It's common for a page or app to have unsubmitted analytics or other data at the
time a user closes it. To prevent data loss, some sites use a synchronous call
XMLHttpRequest() to keep the page or app open until its data is passed to
the server. Not only are there better ways to save data, but this technique creates
a bad user experience by delaying closing of the page for up to several seconds.
This practice needs to change, and browsers are responding. The
specification is already slated for deprecation and
removal. Chrome 80 takes the first
step by disallowing synchronous calls inside several event handlers,
they are fired in the dismissal. WebKit also recently landed a commit implementing
the same behavior change.
In this article I'll briefly describe options for those who need time to update
their sites and outline the alternatives to
Chrome does not simply want to pull the plug on
XMLHttpRequest(), which is why a few
temporary opt-out options are available. For sites on the internet, an origin
With this, you add an origin-specific token to your page headers that enables
XMLHttpRequest() calls. This option ends shortly before Chrome 89
ships, sometime in March 2021. Enterprise Chrome customers can also
AllowSyncXHRInPageDismissal policy flag, which ends at the same time.
Regardless of how you send data back to the server, it's best to avoid waiting
until page unload to send all the data at once. Aside from creating a bad user
experience, unload is unreliable on modern browsers and risks data loss if
something goes wrong. Specifically, unload events often don't fire on mobile
because there are many ways to
tab or browser on mobile operating systems without the
unload event firing.
XMLHttpRequest(), using small payloads was a choice. Now it's a
requirement. Both of its alternatives have an upload limit of 64 KB per
context, as required by the specification.
The Fetch API
provides a robust means of dealing with server interactions and a consistent
interface for use across different
platform APIs. Among its options is
keepalive, which ensures that a request
continues whether or not the page that made it stays open:
fetch() method has the advantage of greater control over what's sent to
the server. What I don't show in the example is that
fetch() also returns a
promise that resolves with a
Response object. Since I'm trying to get out of the
way of the page's unloading, I chose not to do anything with it.
actually uses the Fetch API under the hood, which is why it has the same
64 KB payload limitation and why it also ensures that a request continues
after a page unload. Its primary advantage is its simplicity. It lets you
submit your data with a single line of code:
With the increased availability of
XMLHttpRequest() will hopefully be removed
from the web platform at some point. Browser vendors agree it should be removed, but it will
take time. Deprecating one of its worst use cases is a first step that improves
the user experience for everyone.