391

Possible Duplicate:
Is there a way to detect if a browser window is not currently active?

I have a function that is called every second that I only want to run if the current page is in the foreground, i.e. the user hasn't minimized the browser or switched to another tab. It serves no purpose if the user isn't looking at it and is potentially CPU-intensive, so I don't want to just waste cycles in the background.

Does anyone know how to tell this in JavaScript?

Note: I use jQuery, so if your answer uses that, that's fine :).

Community
  • 1
  • 1
ckknight
  • 5,303
  • 4
  • 22
  • 23
  • 22
    +1 would like to know the answer. my concern is not CPU-intensive but instead bandwidth and server intensive. – mauris Nov 19 '09 at 01:03
  • If you want a Jquery plugin.. https://github.com/keithhackbarth/jquery-window-active – keithhackbarth Apr 09 '13 at 16:10
  • 7
    **Update:** As of 2013 all major browsers provide support for the so-called [visiblity API](https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API?redirectlocale=en-US&redirectslug=DOM/Using_the_Page_Visibility_API). See here for a sample: http://stackoverflow.com/a/19519701/603003 – ComFreek Oct 23 '13 at 14:07
  • I think the best sample is at http://daniemon.com/tech/webapps/page-visibility/ put on your headphones and play and you will see (after you start the video) that the implementation is spot-on. – Walter Vehoeven Feb 19 '20 at 10:49
  • 1
    Use `document.addEventListener("visibilitychange", onchange);` see https://stackoverflow.com/a/1060034/1066234 and https://www.w3.org/TR/page-visibility/ – Avatar Jul 10 '20 at 11:44

6 Answers6

411

In addition to Richard Simões answer you can also use the Page Visibility API.

if (!document.hidden) {
    // do what you need
}

This specification defines a means for site developers to programmatically determine the current visibility state of the page in order to develop power and CPU efficient web applications.

Learn more (2019 update)

gearsdigital
  • 12,634
  • 6
  • 39
  • 69
  • 39
    +1 for giving an answer which doesn't rely on jQuery. This also seems like the best answer in the long run, as browsers move toward supporting W3C standards. David Walsh's example worked for me on Chrome and Firefox, but not Safari. – kronion Jan 04 '14 at 22:38
  • 4
    Visibility and focus are completely different things. – Maciej Krawczyk Jun 13 '16 at 10:46
  • I have a websocket spitting data multiple times per second. As soon as I pick another tab the memory usage skyrockets! Wrapping my code between this answer keep stuff under control. Many thanks! – neric Sep 08 '16 at 09:40
  • 9
    Page visibility API detects if the browser is visible, e.g not minimized or completely covered by another window. It doesn't detect the case where the window is visible but an another window is active. – Juha Syrjälä Jul 25 '17 at 19:37
  • 3
    FYI: http://caniuse.com/#search=Page%20Visibility – James Haug Aug 09 '17 at 16:09
  • Tnx 4 this clean solution, however, you maybe would like to consider checking also document.webkitHidden, mozHidden, msHidden as described here: https://stackoverflow.com/a/19519701/4572425 – Dudi Oct 02 '17 at 12:59
  • 5
    @ckknight do you mind changing the accepted answer to this one? This updated answer is the one we should be using in 2019 – Matt Westlake May 22 '19 at 14:12
  • 2
    “Page Visibility Level 2 replaces the first version of `[PAGE-VISIBILITY]` and includes: …… `Document.hidden` is historical. **Use `Document.visibilityState` instead.**” – Константин Ван Jul 24 '19 at 00:48
  • 1
    [Safari is supported now](https://developer.mozilla.org/en-US/docs/Web/API/Document/hidden#Browser_compatibility) `document.hidden` including Safari – Arseniy-II Aug 29 '19 at 05:27
  • 1
    @JuhaSyrjälä That's a good thing for most people, if it's visible then data should still be polling imho unless you got some different use case, especially if you're referring to multiple monitors :| – zanderwar Mar 28 '20 at 16:27
  • 2
    @КонстантинВан Only the W3C could create a draft with a recommendation that **voids and replaces itself** with another recommendation from the very same draft. – andreszs Apr 17 '20 at 14:40
  • 1
367

You would use the focus and blur events of the window:

var interval_id;
$(window).focus(function() {
    if (!interval_id)
        interval_id = setInterval(hard_work, 1000);
});

$(window).blur(function() {
    clearInterval(interval_id);
    interval_id = 0;
});

To Answer the Commented Issue of "Double Fire" and stay within jQuery ease of use:

$(window).on("blur focus", function(e) {
    var prevType = $(this).data("prevType");

    if (prevType != e.type) {   //  reduce double fire issues
        switch (e.type) {
            case "blur":
                // do work
                break;
            case "focus":
                // do work
                break;
        }
    }

    $(this).data("prevType", e.type);
})

Click to view Example Code Showing it working (JSFiddle)

Dean Meehan
  • 2,321
  • 17
  • 33
Richard Simões
  • 11,197
  • 5
  • 38
  • 50
  • does that works? tested? that simple? – mauris Nov 19 '09 at 01:07
  • @thephpdeveloper: Sure. If you have firebug, try a simple `console.log('test')` call for either event. – Richard Simões Nov 19 '09 at 01:11
  • Works great. I start an interval in focus and stop it on blur. – ckknight Nov 19 '09 at 01:30
  • It doesn't work on FF 4 and higher :/ – WooCaSh Aug 19 '11 at 08:36
  • 8
    This answer is not optimal because `focus` and `blur` events can often fire more than one time in the browser for each conceptual Focus or Blur action taken by the user, in which case the client will start doing `hard_work` on more than one interval, basically simultaneously. – Jon z Oct 01 '11 at 13:01
  • @jon-z, how about that adjustment? – Richard Simões Oct 02 '11 at 20:40
  • i for example see that blur does not fire up when i switch between applications, but does work when i switch between tabs on Mac OS, and on firefox/chrome/safari ... – GnrlBzik Nov 22 '11 at 10:00
  • 3
    I've read elsewhere that `onmousemove` could be a viable replacement for `focus`. – Michael Robinson Sep 19 '12 at 06:15
  • 1
    @MichaelRobinson Maybe for maximized/fullscreen tabbed browsers. It may still fire in Internet Explorer (http://www.bit-tech.net/news/bits/2012/12/13/ie-bug-cursor/1), although the focus is on some other application. – Tiberiu-Ionuț Stan Feb 13 '13 at 15:44
  • 1
    But what if the user switches tab whilst the page loads, before `$(window)focus/blur` has been called? Depending on your use case, this might mess up the callback status, and any background job? (For example, if you start the background job on page load — but `blur` never happens, because the user switched tabs before `$(window).blur` was registered?) – KajMagnus Feb 22 '13 at 11:58
  • This also doesn't work if the user clicks an iframe within the page. – red Nov 21 '13 at 16:11
  • You saved my day. The Switch case with blur/focus worked perfectly in desktop and ios devices. – Jimba Tamang Dec 23 '14 at 23:09
  • try http://daniemon.com/tech/webapps/page-visibility/ works better I think – Walter Vehoeven Feb 19 '20 at 10:50
157

I would try to set a flag on the window.onfocus and window.onblur events.

The following snippet has been tested on Firefox, Safari and Chrome, open the console and move between tabs back and forth:

var isTabActive;

window.onfocus = function () { 
  isTabActive = true; 
}; 

window.onblur = function () { 
  isTabActive = false; 
}; 

// test
setInterval(function () { 
  console.log(window.isTabActive ? 'active' : 'inactive'); 
}, 1000);

Try it out here.

Andrew
  • 3,330
  • 1
  • 33
  • 53
Christian C. Salvadó
  • 723,813
  • 173
  • 899
  • 828
19

Using jQuery:

$(function() {
    window.isActive = true;
    $(window).focus(function() { this.isActive = true; });
    $(window).blur(function() { this.isActive = false; });
    showIsActive();
});

function showIsActive()
{
    console.log(window.isActive)
    window.setTimeout("showIsActive()", 2000);
}

function doWork()
{
    if (window.isActive) { /* do CPU-intensive stuff */}
}
Chris Fulstow
  • 38,141
  • 9
  • 83
  • 109
8

All of the examples here (with the exception of rockacola's) require that the user physically click on the window to define focus. This isn't ideal, so .hover() is the better choice:

$(window).hover(function(event) {
    if (event.fromElement) {
        console.log("inactive");
    } else {
        console.log("active");
    }
});

This'll tell you when the user has their mouse on the screen, though it still won't tell you if it's in the foreground with the user's mouse elsewhere.

Daniel Quinn
  • 4,647
  • 3
  • 31
  • 50
  • 2
    Good outside the box thinking; however, it wouldn't work very well if you were trying to figure out how long a user stays on a page. Also, `hover` is not a valid option for mobile browsers. To be fair though, I have no idea if the `focus` or `blur` event binding would work on mobile devices. – Edwin Apr 27 '12 at 03:09
  • 1
    also, hover depends on a mouse move. if the tab was entered using a keyboard shortcut, then the hover is probably not triggered. – Kae Verens Jan 04 '13 at 20:39
7

If you are trying to do something similar to the Google search page when open in Chrome, (where certain events are triggered when you 'focus' on the page), then the hover() event may help.

$(window).hover(function() {
  // code here...
});
Chris
  • 5,396
  • 1
  • 35
  • 65
Trav L
  • 13,104
  • 5
  • 28
  • 37