16

I'm working on a chat and I'm trying to figure out how I can detect that the user has left the page or not. Almost everything is being handled by the database to avoid the front end from messing up.

So what I'm trying to do is once the page is left for any reason (window closed, going to another page, clicking a link, etc.) an ajax call will be fired before a person leaves so I can update the database.

This is what I've tried:

$(window).unload(function(){
      $.post("script.php",{key_leave:"289583002"});
});

For some odd reason, it wouldn't work, and I've checked the php code, and it works fine. Any suggestions?

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
Majo0od
  • 2,278
  • 10
  • 33
  • 58
  • Possible duplicate of [JavaScript, browsers, window close - send an AJAX request or run a script on window closing](http://stackoverflow.com/questions/6162188/javascript-browsers-window-close-send-an-ajax-request-or-run-a-script-on-win) – Michał Perłakowski Jan 12 '17 at 09:55
  • look at my answer here: https://stackoverflow.com/questions/4945932/window-onbeforeunload-ajax-request-in-chrome/55651530#55651530 – sNICkerssss Apr 12 '19 at 12:24

5 Answers5

38

Try this:

$(window).unload(function(){
    $.ajax({
        type: 'POST',
        url: 'script.php',
        async:false,
        data: {key_leave:"289583002"}
    });
});

Note the async:false, that way the browser waits for the request to finish.

Using $.post is asynchronous, so the request may not be quick enough before the browser stops executing the script.

stewe
  • 41,820
  • 13
  • 79
  • 75
  • My goodness it worked! Thank you very much, learned something new today :-) – Majo0od Apr 22 '12 at 23:05
  • 7
    The code above works well but as of jQuery 1.8 the .unload() method was [deprecated](http://api.jquery.com/unload/) and replaced with ```$(window).on('unload', function() {});``` – Brent Matzelle Mar 21 '14 at 21:03
  • 1
    This might be OK as far as it goes, but what if the user experiences a power cut, for example. Better would be something that says "I'm still here" (heartbeat) rather than "I'm leaving now". – Nick Rice Mar 29 '16 at 08:12
  • 2
    Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. – aldrien.h Jul 20 '16 at 03:23
4

This isn't the correct way of doing this... Suppose the OS just hangs or something happens in the browsers process then this event wont be fired. And you will never ever know when the user has left, showing him/her online ever after he/she has disconnected. Instead of this, what you can do is.

  1. Try connecting a socket so that you can know the user is disconnected when the socket is disconnected
  2. You can send a request to the server (say after every 1 sec) so that you can know that the user is still connected. If you didn't receive the request - even after 2 secconds - disconnect the user.
Parv Sharma
  • 12,581
  • 4
  • 48
  • 80
  • I don't know how to do that, do you have an example? – Majo0od Apr 22 '12 at 22:40
  • what r u using server side? asp.net ? – Parv Sharma Apr 22 '12 at 22:41
  • 1
    He is using PHP. Here is nice source which can help you get started https://github.com/nicokaiser/php-websocket Also it has SWF object for socket implementation for browsers which do not support web sockects. – Milan Jaric Apr 22 '12 at 22:44
  • Surprised this answer was at -1. Just raised it to 0. Maybe it's not as well written as it might be but it makes a very important point and suggests solutions. – Nick Rice Mar 29 '16 at 08:16
  • Option number 2 is exactly what I'm trying to do. I know how the ajax should be but do you have any suggestions on how I can do this in Django's side? – aaronn Apr 21 '22 at 12:21
  • @aaronn - this might help https://channels.readthedocs.io/en/stable/ – Parv Sharma Apr 24 '22 at 08:49
1

Try to add popup (prompt("leaving so early?")) after $.post. It may work. Tho it may be bad user experience. :)

Milan Jaric
  • 5,556
  • 2
  • 26
  • 34
  • I doubt it will work with any variation, many browsers have different policies when browser is closing or just tab is closing or even page url is redirected to other url. Bigest problem here is that when page is "closing" all connections and other stuff is disposed! So even you send POST request few milliseconds before page is disposed there is big chance that connection will be terminated... That is why I suggested you to use prompt after $.post function call. I will try to create sample but I can't promise anything. – Milan Jaric Apr 22 '12 at 22:36
0

This is related to the answer above. https://stackoverflow.com/a/10272651/1306144

This will execute the ajax call every 1 sec. (1000)

function callEveryOneSec() {
    $jx.ajax({}); // your ajax call
}

setInterval(callEveryOneSec, 1000);
Community
  • 1
  • 1
Edesa
  • 581
  • 7
  • 16
  • 2
    I think sending AJAX every one second can kill the server when will be many users... – Siper Mar 23 '17 at 22:07
  • On Django how can I handle this? How can I find out that it's been more than a second since a request has been sent. – aaronn Apr 21 '22 at 12:26
0

The unload event is not recommended to detect users leaving the page. From MDN:

Developers should avoid using the unload event ... Especially on mobile, the unload event is not reliably fired.

Instead, use the visibilitychange event on document and/or the pagehide event on window (see links for details). For example:

document.addEventListener('visibilitychange', function() {
    if (document.visibilityState === 'hidden') {
        $.ajax({
            type: 'POST',
            url: 'script.php',
            async:false,
            data: {key_leave: "289583002"}
        });
    }
});

Better yet, use Navigator.sendBeacon, which is specifically designed for the purpose of sending a small amount of analytics data to a server:

document.addEventListener('visibilitychange', function() {
    if (document.visibilityState === 'hidden') {
         navigator.sendBeacon('script.php', {key_leave: "289583002"});
    }
});
Richard Ye
  • 685
  • 4
  • 12