Created by potrace 1.16, written by Peter Selinger 2001-2019Navigate back to the homepage

Sending asynchronous requests after leaving a page

Amr Elsekilly
November 28th, 2021 · 2 min read


Most of us must have struggled in the past with sending asynchronous requests when a user decides to leave a page. Whether you’re trying to send analytics data or sending a small application-specific data to the backend when the user decides to leave your page.

Most probably you’ve faced this unreliability. And tried to find workarounds to overcome this reliability which could have caused a bad UX as a result.

In this article we’ll be going through these browser limitations, and how to address them in order to send asynchronous requests properly when the user tries to leave your page.

How can we detect that a user has left our page?

There are a couple of APIs and events that the browser gives us to detect that a user has left our page. In the next section we’ll go through them and discuss their limitations and where to use each of them.

The pagehide, beforeunload, and unload events

You can read more about them on MDN, and in this great google developers article.

The problem with using them is that they’re very unreliable and unpredictable. That’s why it’s always better to rely on the browser’s visibility API.

The Browser’s Visibility API

The Browser/Page Visibility API allows us to detect if a page is visible or hidden, thus can know when a user leaves your page.

Usually, leaving a page doesn’t just mean that a user has closed the tab. If we’re talking about opening the page on a mobile browser, using the visibility API will allow us to detect if the user switches to a different mobile app which means that they’re done using our page or when they decide to close the browser using the phone’s app manager. We can’t do that using unload and beforeunload.

Nice, now that we know how to detect the event of the user leaving the page. How will we send a request to our backend?

How to send data to the backend when a user leaves a page

When we’re sending HTTP requests to our backend, we usually send asynchronous XMLHttpRequest requests.

The problem with that, is that if the browser is trying to unload your page or if the tab is hidden/invisible, modern browsers most of the time will decide to not fire any asynchronous XMLHttpRequest requests. Thus, this method could become very unreliable for sending data to our backend, and most of the time it won’t work. I struggled with that A LOT in the past. You can read more about this in this amazing MDN article.

The solution to sending the request reliably

Given the limitations of using XMLHttpRequest in the mentioned case, browsers created a method called sendBeacon() which fixed this issue.

The Navigator.sendBeacon() Method

This method allows you to send a small amount of data asynchronously to a RESTful API over HTTP.

The interface for this method looks like this

1navigator.sendBeacon(URL, data);

Where URL is the URL of your RESTful endpoint that should receive the data. And data is the small amount of data that you’re trying to send to your backend, whether it’s an analytics data or whatever.

You can read more about that method in this MDN article.

Note: Based on my own experience, for more reliability it’s better to serialize any data you wanna send and send it as a string.

The complete solution

When we combine the visibility change event with the sendBeacon() method, we get the following

1document.addEventListener('visibilitychange', function logData() {
2 if (document.visibilityState === 'hidden') {
3 navigator.sendBeacon('', 'serializedData');
4 }

Here we’re listening to the visibility change event, and if the page becomes invisible or the user leaves your page we will send the request using sendBeacon() to your RESTful endpoint.

If you liked the article, please don’t forget to subscribe to my mailing list, to get my future articles. Thanks! 🚀🔥

Join my mailing list to get notified about new content

Be the first to receive my latest content with the ability to opt-out at anytime. I promise not to spam your inbox or share your email with any third parties.

More articles from Amr Elsekilly

Succinct/concise syntax for optional object keys in ES6

Did you ever need to type a condition to add a new key to your JS object? This article has an ES6 shortcut for you!

March 6th, 2021 · 1 min read

TMux saving the day in 2020 [A Step-By-Step Guide] 🔥

Throughout the years, tmux has been on the top of the productivity tools that I use on a daily basis. It allows me to manage multiple projects simultaneously with ease in the terminal.

July 6th, 2020 · 2 min read
© 2020–2023 Amr Elsekilly
Link to $ to $ to $ to $ to $