Sending AJAX Data when User Moves Away / Exits from Page

Use-Cases of this Tutorial

  • You are looking to send data to server before the user moves away from the current page.
  • You are looking to know the working of navigator.sendBeacon method.

It is sometimes required that your application sends an AJAX to the server before the user moves away from the page (goes to another page, reloads the page, closes the browser etc).

As an example, if you have to calculate the time user spends on the page, you have to wait until the time user moves away from the page. Once he exits the page, your application must send the time spend via AJAX to your server, where you can save the data.

Another good use-case is where a user is uploading images for a "post". Each time he uploads an image, it is saved to server. But unfortunately the user instead of saving the post, simply closes his browser. The images that he uploaded, now belong to no one and server's disk space is simply being wasted. It would be better if the application simply deletes the images in such a scenario.

This tutorial will tell what should you do in such similar cases.

Using unload Event to Detect Page Unloading

unload event is fired when the current document is being unloaded from memory. Nothing is visible to the user anymore, and any interactions on the page won't work.

$(window).on('unload', function() {
	// do something
});

You can use this event to send an AJAX request to the server. But if it is a normal aynschronous AJAX request then there is no guarantee that it will be send successfully to the server. Browsers will typically ingore aynschronous requests to the server. It may, or may not be send.

However there are some methods through which you can achieve this.

Method 1 - Send a Synchronous AJAX

You can send a synchronous AJAX request inside the unload event. The disadvantage is that it will "block" the unloading of the document. If the user is trying to move to a new page, it'll be slower - he can only move to the next page once the synchronous AJAX request is finished. The user will think that the new page is slower, however the the culprit is the synchronous AJAX call.

The good thing is that it will work in all browsers. If you have no option except to use this method, make sure you are sending a fast response from the server.

$(window).on('unload', function() {
	// async: false will make the AJAX synchronous in case you're using jQuery
	$.ajax({
        type: 'POST',
        url: 'ajax.php',
        data: { ajax_data : 22 },
        async: false
    });
});

Method 2 - Sending an Asynchronous AJAX & Ignoring AJAX Abort on Server

The problem with sending an asynchronous AJAX inside the unload event is that the browser may abort the AJAX request when the document is being unloaded. The AJAX request is send, but it is aborted later.

PHP has a ignore_user_abort function that will ignore the script abort. This means that even if the browser aborted the AJAX, it will still be executed on the server.

$(window).on('unload', function() {
	// Asynchronous AJAX
	$.ajax({
        type: 'POST',
        url: 'ajax.php',
        data: { ajax_data : 22 }
    });
});
<?php
ignore_user_abort(true);

// do something with $_POST['ajax_data']

?>

However there is a slight possibility that this method may not work on your server. ignore_user_abort depends a lot upon the server configuration.

It would be great if you can leave a comment below whether this method worked for you or not.

Method 3 - Using navigator.sendBeacon to Send Data Asynchronously to the Server

navigator.sendBeacon is a new method introduced by browsers that solves the problem of sending data to server on document unload. Data is transmitted asynchronously without affecting loading performance of the next page. Data is send reliably - the method returns true if the browser successfully queues the data for transfer, and false otherwise. However this method does not provide any information whether the data transfer succeeded or not.

This is the best method, however because it is new, there are browser compatibilty issues. Firefox, Chrome, Opera & Edge support it. Safari and IE don't support it. However it is only a matter of time before this method becomes mainstream.

$(window).on('unload', function() {
	// You can send an ArrayBufferView, Blob, DOMString or FormData
	// Since Content-Type of FormData is multipart/form-data, the Content-Type of the HTTP request will also be multipart/form-data
	var fd = new FormData();
	fd.append('ajax_data', 22);

	navigator.sendBeacon('ajax.php', fd);
});
<?php

// do something with $_POST['ajax_data']

?>

navigator.sendBeacon sends a HTTP POST request. Also Beacon API does not provide a response callback (You won't even see a response in browser developer tools).

Here is a polyfill for sendBeacon. If the method is not available in the browser, it will send a synchronous AJAX.

Special Consideration for Mobile Devices

There is one thing that you should keep in mind while sending data to server on page unload. unload event is not guaranteed to be called in a mobile device. For example, if a browser page is in the background state, and if the mobile OS decides to terminate the browser process, unload event will not be fired.

But visibilitychange event is guaranteed to be fired by a mobile browser. Keep this in mind while developing your application.

Page Visibility API is a good introduction to visibilitychange event.

Setting HTTP Headers in a Beacon Request