Home > jquery > jQuery idleTimer plugin

jQuery idleTimer plugin

There are a few cases where you want to know if the user is idle. Namely:

  • You want to preload more assets
  • You want to grab their attention to pull them back
  • You want close their banking session after 5 minutes of inactivity. (Jerk!)
  • You want the site to sneak off the screen and see if they notice ;-)

Nick Zakas wrote a script for YUI3 to handle these cases. His writeup has a great description of the architecture approach he took to the script.

In my jQuery adaptation, I did a few different things:

  1. Leveraged event namespaces for easy unbinding
  2. Considered mousewheel as activity, in addition to keyboard and mouse movement.
  3. Gave it a bit more jQuery-ish of an API

To use:

// idleTimer() takes an optional argument that defines the idle timeout
// timeout is in milliseconds; defaults to 30000
$.idleTimer(10000);
 
 
$(document).bind("idle.idleTimer", function(){
 // function you want to fire when the user goes idle
});
 
 
$(document).bind("active.idleTimer", function(){
 // function you want to fire when the user becomes active again
});
 
// pass the string 'destroy' to stop the timer
$.idleTimer('destroy');

Get the source on github (4.6k unminified)
View the demo

Note: If you want to change the timeout interval, you'll have to destroy the existing timer first.

2009.09.22: I've updated the idleTimer script for a few more features…
// you can query if the user is idle or not with data()
$.data(document,'idleTimer');  // 'idle'  or 'active'
 
// you can get time elapsed since user when idle/active
$.idleTimer('getElapsedTime'); // time since state change in ms

You can get the latest code, naturally, on github.

Paul Irish jquery

  1. Nate
    | #1

    This looks very useful. You should add the destroy trick to infinite scroll.

  2. | #2

    @Nate, I'm about to do some infinite scroll upgrades, and destroy is certainly a good call. Thx Nate!

  3. SlexAxton
    | #3

    Great work Paul. I'm gonna find a reason to use this nice and soon.

  4. Einar
    | #4

    A tiny non–issue — it doesn't register me as active on just a mouse click, without moving the mouse.

  5. | #5

    @Einar, Aye. I suppose a click should be included. (Though it'd be hard to click without mouse movement, eh) But the overhead is pretty minimal. :)

    FWIW it currently watches these events: 'mousemove keydown DOMMouseScroll mousewheel'. I'll throw click in, too.

  6. | #6

    Very nice, I can see this being used for a web-based chat script.

  7. Kris
    | #7

    Thanks a ton! I have been thinking about something like this for a while now.

  8. | #8

    Great i found my solution..

  9. | #9

    Hi I'm using this plugin and it's working very well except for one problem. It seems to be interfering with the jQuery ui dialog feature. When I include $.idleTimer(120000) in my script firebug shows a 'too much recursion' error when I attempt to close an open modal dialog. When I remove that line of code it works fine. Any ideas? Thanks in advance.

  10. | #10

    @Marc Thanks for the bug report Marc. It looks to be interfering with any unbind() calls that use namespaces. In this case: $(document).unbind('.dialog-overlay')

    Turns out that $(foo).bind('click.bar mousewheel.bar ',fn) causes a recursive loop in $.event.remove(). {There's an extra space}

    Gave it a quick $.trim() and we're back in business.

    Committed to github with version 0.6.080605.

  11. | #11

    Wow amazingly quick response thanks - Got everything fixed before I could even get back from work! @Paul Irish

  12. ezod
    | #12

    Hi,
    great plugin, but I think there´s a little bug (tested on the demo site):

    If you are idle and simply click the mousebutton (without moving the mouse) the "active.idleTimer" is fired but the idle timer doesn´t work anymore ;)

    greetz
    ezod

  13. | #13

    @ezod Good catch. The script didn't restart the timeout after it changed states. (It would be waiting for the next user event.)

    Fixed and updated everywhere as ver 0.7.080609.

  14. | #14

    $.idleTimer('destroy');
    Don't forget this!

  15. Joel Holder
    | #15

    Looks as though idleTimer doesn't pickup movements over an iframe. When I have idleTimer setup on a parent page and I move my cursor just within the boundary of an iframe on page, the idle.idleTimer still fires its function, then immediately fires active.idleTimer.

  16. pisces
    | #16

    Hi
    I am trying to use the idle timer for implementing Session time out in my application.
    My concern is that if user opens multiple browser windows for the same session(ctrl+N for IE6) and is active on one of the windows the user shouldnt time out
    Is there any way I can use this timer to implement this?

    I was thinking of having a session cookie and updating the last hit time whenever the user goes active on any window.
    Then Check if the time out is reached by comparing the last hit with the current time at periodic intervals of idle time .

    My application is a sessionless application .
    Pls suggest some possible way.

  17. | #17

    @pisces Your cookie technique seems reasonable. Probably the best way to handle that I can think of at the moment.

  18. ezhh
    | #18

    Thank you very much!!!
    Very nice and useful.
    1 minute and dream become true =)

  19. Aury
    | #19

    This is great, but it doesn't work if the user is moving the mouse/using the keyboard in an embedded flash file. I don't suppose there's a workaround for that?

  20. | #20

    @Aury Newp. Flash and iframes are the two obvious areas where this fails.

  21. agask2
    | #21

    Aury seems right is there any way to get this to detect movement in side of a particular frame. Eg the javascript is on the main page then i have 3 frames It would be nice to monitor the one frame but so far no go. Ive tried $(frames["content"].document).bind( and it appears it only works when transitioning or moving over one frame to another not just sitting in the same frame?? any ideas?

  22. | #22

    @agask2 You'd have to have this script running in each frame, and then tell the top frame the results via window.postMessage() or this sort of thing.

    Not terribly trivial.

    // this is half of what you'd need...
    $(document).bind("idle.idleTimer", function(){
     $.postMessage('idle down here!',top.location.href);
    }).bind('active.idleTimer',function(){
     $.postMessage('active down here!',top.location.href);
    });
  23. agask2
    | #23

    @Paul Irish
    thanks good input! But my problem is I do not know what will be the src for the frame will be. So I cannot put javascript there,It could be google or anything really. I just need the javascript on the outside to montior what is inside the frame for movement. Any ideas there??

  24. | #24

    This is exactly what I was looking for.
    Thanks, Paul :)

  25. | #25

    @agask2
    Frames are tricky and they don't bubble up things like mousemovement to the parent frame. And then due to the Same Origin Policy, you can't inject script into them at will. So you're in a tough place. :)

    One technique is to run the pages through a local proxy and inject script into them. That sounds like not fun, though. :/

  26. agask2
    | #26

    @Paul Irish
    ouch.. yah, I do not foresee that as being an option really. Can you inject script if everything is on the same domain?? maybe? without a proxy? Thanks for all your support thus far. Its a real nice script for a single page.

  27. | #27

    @agask2 If it's on the same domain you could probably hook into it… i think..

    // no guarantees this would work. i'm just guessing
    $($('#iframeid').contents()[0].document).bind("idle.idleTimer", function(){
     top.$(top.document).triggger('idle.idleTimer');
    });
  28. Frank Watts
    | #28

    Silly question, but how can I call the static method isIdle?

    $.idleTimer.isIdle is undefined

  29. | #29

    @Frank Watts ,

    If you want to just indicate (externallY) that the user is idle, you can trigger the custom event:

      $(document).trigger('idle.idleTimer');
  30. Frank Watts
    | #30

    I don't want to trigger it, I want to see what the current status is. The reason is because I have another timer running that will autoscroll a page every 15 minutes. I don't want to autoscroll if the user is not idle.

  31. | #31

    I've updated the script to allow you to query if the user is currently idle or not (through data())

    And to get the elapsed time since the last state change. (If you want to say a user has been idle for x seconds….)

  32. Maikel
    | #32

    It would be great if you could to attach several idleTimer to the document.

    cheers

  33. | #33

    @Maikel

    You indicated the use-case for this would be
    * One Timer to restore the forms, messages boxes, etc.
    * Another Timer to notify about expiration sessions.

    It's a good idea. If other people think it would be useful, I'll add it to the script. (Basically it would bind/trigger on individual elements instead of just the document.)

  34. | #34

    Is there a way to pop up a warning of a pending timeout?
    Like this:
    You're session is about to end, click here to continue browsing.

  35. | #35

    For those wondering about implementing expiring sessions/pending timeout, I wrote a blog post on the subject: http://www.erichynds.com/blog/?p=66

  36. S Kraggerud
    | #36

    If you could implement functionality so we could use several idleTimers that would be great!

  37. Vincent Stoessel
    | #37

    I second the call for a version that can do multiple timers. I have a 5 minute and 20 second timeout warning, and this would be great for that.
    Great work!

  38. Sandeep
    | #38

    @Paul Irish
    $(document).trigger('idle.idleTimer') is not working. It does not execute the function which i have set for idle.idleTimer.

  39. | #39

    will try immediately, thanx for the functions…

  40. Derek
    | #40

    Hey, thanks for this idle timer, it works great. I just can't figure out how to use getElapsedTime. Can it be used to find out how long the user was idle for once they become active again? If so, how?

  41. | #41

    Very useful. Thanks! One question, how exactly do you use the query feature?

    // you can query if the user is idle or not with data()
    $.data(document,'idleTimer'); // 'idle' or 'active'

  1. | #1
  2. | #2
  3. | #3
  4. | #4
  5. | #5
  6. | #6
  7. | #7
  8. | #8
  9. | #9
  10. | #10
  11. | #11

For code blocks, use <pre lang="javascript" escaped="true">. css and html4strict are also accepted.

Comments for this post will be closed on 29 May 2010.