Using the Page Visibility API

  • Revision slug: Web/Guide/User_experience/Using_the_Page_Visibility_API
  • Revision title: Using the Page Visibility API
  • Revision id: 424549
  • Created:
  • Creator: ethertank
  • Is current revision? No
  • Comment CleanUp, Formatting, -ReviewFlag(Template)

Revision Content

Summary

The Page Visibility API lets you know when a webpage is visible or in focus. With tabbed browsing, there is a reasonable chance that any given webpage is in the background and thus not visible to the user. When the user minimizes the webpage or moves to another tab, the API sends a {{event("visibilitychange")}} event regarding the visibility of the page. You can detect the event and perform some actions or behave differently. For example, if your web app is playing a video, it would pause the moment the user looks at another browser, and plays again when the user returns to the tab. The user does not lose their place in the video and can continue watching.

Benefits

The API is particularly useful for saving resources by giving developers the opportunity to not perform unnecessary tasks when the webpage is not visible.

Use cases

A few examples:

  • A site has an image carousel that shouldn't advance to the next slide unless the user is viewing the page.
  • An application showing a dashboard of information doesn't want to poll the server for updates when the page isn't visible.
  • A page wants to detect when it is being prerendered so it can keep accurate count of page views.

Developers have historically used imperfect proxies to detect this. For example, registering an onblur/onfocus handler on the window helps you know when your page is not the active page, but it does not tell you that your page is hidden to the user. The Page Visibility API addresses this. (When compared with registering onblur/onfocus handlers on the window, a key difference is that a page does not become hidden when another window is made active and the browser window loses focus. A page only becomes hidden when the user switches to a different tab or minimizes the browser window.)

Example

View live example (video with sound).

The example, which pauses the video when you switch to another tab and plays again when you return to its tab, was created with the following code:

// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
  hidden = "mozHidden";
  visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}
 
var videoElement = document.getElementById("videoElement");

// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
  if (document[hidden]) {
    videoElement.pause();
  } else {
    videoElement.play();
  }
}

// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || 
  typeof hidden === "undefined") {
  alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
  // Handle page visibility change   
  document.addEventListener(visibilityChange, handleVisibilityChange, false);
    
  // Revert to the existing favicon for the site when the page is closed;
  // otherwise the favicon remains paused.png
  window.addEventListener("unload", function(){
    favicon.change("/favicon.ico");
  }, false);
    
  // When the video pauses, set the favicon.
  // This shows the paused.png image
  videoElement.addEventListener("pause", function(){
    favicon.change("images/paused.png");
  }, false);
    
  // When the video plays, set the favicon.
  videoElement.addEventListener("play", function(){
    favicon.change("images/playing.png");
  }, false);
    
  // set the document (tab) title from the current video time
  videoElement.addEventListener("timeupdate", function(){
    document.title = Math.floor(videoElement.currentTime) + " second(s)";
  }, false);
}

Methods overview

document.hidden

Returns true if the page is in a state considered to be hidden to the user, and false otherwise.

document.visibilityState

Returns a string denoting the visibility state of the document. Possible values:

  • visible : the page content may be at least partially visible. In practice this means that the page is the foreground tab of a non-minimized window.
  • hidden : the page content is not visible to the user. In practice this means that the document is either a background tab or part of a minimized window.
  • prerender : the page content is being prerendered and is not visible to the user (considered hidden for purposes of document.hidden). The document may start in this state, but will never transition to it from another value.
//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
  if (document.hidden) {
    pauseSimulation();
  } else  {
    startSimulation();
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

Note

Visibility states of an {{HTMLElement("iframe")}} is as same as the parent document. Hiding the iframe with CSS properties does not trigger visibility events nor change the state of the content document.

Specifications

Specification Status Comment
W3C Page Visibility API {{Spec2('Page Visibility API')}}  

Browser compatibility

{{CompatibilityTable}}
Feature Chrome (Webkit) Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support 13 {{property_prefix("webkit")}} {{CompatGeckoDesktop(10)}} {{property_prefix("moz")}}
{{CompatGeckoDesktop(18)}}
10 {{property_prefix("ms")}} 12.10[*] Nightly build
Feature Android Firefox Mobile (Gecko) IE Phone Opera Mobile Safari Mobile
Basic support {{CompatNo}} {{CompatGeckoMobile(10)}} {{property_prefix("moz")}}
{{CompatGeckoMobile(18)}}
{{CompatUnknown}} 12.10[*] {{CompatNo}}

[*] Doesn't fire the {{event("visibilitychange")}} event when the browser window is minimized, nor set hidden to true.

See also

Revision Source

<h2 id="Summary">Summary</h2>
<p><span class="seoSummary">The <strong>Page Visibility API</strong> lets you know when a webpage is visible or in focus.</span> With tabbed browsing, there is a reasonable chance that any given webpage is in the background and thus not visible to the user. When the user minimizes the webpage or moves to another tab, the API sends a {{event("visibilitychange")}} event regarding the visibility of the page. You can detect the event and perform some actions or behave differently. For example, if your web app is playing a video, it would pause the moment the user looks at another browser, and plays again when the user returns to the tab. The user does not lose their place in the video and can continue watching.</p>
<h3 id="Benefits">Benefits</h3>
<p>The API is particularly useful for saving resources by giving developers the opportunity to not perform unnecessary tasks when the webpage is not visible.</p>
<h3 id="Use_cases">Use cases</h3>
<p>A few examples:</p>
<ul>
  <li>A site has an image carousel that shouldn't advance to the next slide unless the user is viewing the page.</li>
  <li>An application showing a dashboard of information doesn't want to poll the server for updates when the page isn't visible.</li>
  <li>A page wants to detect when it is being prerendered so it can keep accurate count of page views.</li>
</ul>
<p>Developers have historically used imperfect proxies to detect this. For example, registering an onblur/onfocus handler on the window helps you know when your page is not the active page, but it does not tell you that your page is hidden to the user. The Page Visibility API addresses this. (When compared with registering onblur/onfocus handlers on the window, a key difference is that a page does <em>not</em> become hidden when another window is made active and the browser window loses focus. A page only becomes hidden when the user switches to a different tab or minimizes the browser window.)</p>
<h2 id="Example" name="Example">Example</h2>
<p>View <a href="http://www.samdutton.com/pageVisibility/">live example</a> (video with sound).</p>
<p>The example, which pauses the video when you switch to another tab and plays again when you return to its tab, was created with the following code:</p>


<pre class="brush: js">
// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
  hidden = "mozHidden";
  visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}
 
var videoElement = document.getElementById("videoElement");

// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
  if (document[hidden]) {
    videoElement.pause();
  } else {
    videoElement.play();
  }
}

// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || 
  typeof hidden === "undefined") {
  alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
  // Handle page visibility change   
  document.addEventListener(visibilityChange, handleVisibilityChange, false);
    
  // Revert to the existing favicon for the site when the page is closed;
  // otherwise the favicon remains paused.png
  window.addEventListener("unload", function(){
    favicon.change("/favicon.ico");
  }, false);
    
  // When the video pauses, set the favicon.
  // This shows the paused.png image
  videoElement.addEventListener("pause", function(){
    favicon.change("images/paused.png");
  }, false);
    
  // When the video plays, set the favicon.
  videoElement.addEventListener("play", function(){
    favicon.change("images/playing.png");
  }, false);
    
  // set the document (tab) title from the current video time
  videoElement.addEventListener("timeupdate", function(){
    document.title = Math.floor(videoElement.currentTime) + " second(s)";
  }, false);
}
</pre>

<h2 id="Methods_overview">Methods overview</h2>
<h3 id="document.hidden"><code>document.hidden</code></h3>
<p>Returns <code>true</code> if the page is in a state considered to be hidden to the user, and <code>false</code> otherwise.</p>
<h3 id="document.visibilityState"><code>document.visibilityState</code></h3>
<p>Returns a <code>string</code> denoting the visibility state of the document. Possible values:</p>
<ul>
  <li><code>visible</code> : the page content may be at least partially visible. In practice this means that the page is the foreground tab of a non-minimized window.</li>
  <li><code>hidden</code> : the page content is not visible to the user. In practice this means that the document is either a background tab or part of a minimized window.</li>
  <li><code>prerender</code> : the page content is being prerendered and is not visible to the user (considered hidden for purposes of <code>document.hidden</code>).  The document may start in this state, but will never transition to it from another value.</li>
</ul>
<pre class="brush: js">
//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
  if (document.hidden) {
    pauseSimulation();
  } else  {
    startSimulation();
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);
</pre>

<h2 id="Example" name="Example">Note</h2>
<p>Visibility states of an {{HTMLElement("iframe")}} is as same as the parent document. Hiding the iframe with CSS properties does not trigger visibility events nor change the state of the content document.</p>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
  <thead>
    <tr>
      <th scope="col">Specification</th>
      <th scope="col">Status</th>
      <th scope="col">Comment</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html" title="http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html">W3C Page Visibility API</a></td>
      <td>{{Spec2('Page Visibility API')}}</td>
      <td>&nbsp;</td>
    </tr>
  </tbody>
</table>
<h2 id="Browser_compatibility" name="Browser_compatibility">Browser compatibility</h2>
<div>{{CompatibilityTable}}</div>
<div id="compat-desktop">
  <table class="compat-table">
    <tbody>
      <tr>
        <th>Feature</th>
        <th>Chrome (Webkit)</th>
        <th>Firefox (Gecko)</th>
        <th>Internet Explorer</th>
        <th>Opera</th>
        <th>Safari (WebKit)</th>
      </tr>
      <tr>
        <td>Basic support</td>
        <td>13 {{property_prefix("webkit")}}</td>
        <td>{{CompatGeckoDesktop(10)}} {{property_prefix("moz")}}<br />
          {{CompatGeckoDesktop(18)}}</td>
        <td>10 {{property_prefix("ms")}}</td>
        <td>12.10[*]</td>
        <td><em>Nightly build</em></td>
      </tr>
    </tbody>
  </table>
</div>
<div id="compat-mobile">
  <table class="compat-table">
    <tbody>
      <tr>
        <th>Feature</th>
        <th>Android</th>
        <th>Firefox Mobile (Gecko)</th>
        <th>IE Phone</th>
        <th>Opera Mobile</th>
        <th>Safari Mobile</th>
      </tr>
      <tr>
        <td>Basic support</td>
        <td>{{CompatNo}}</td>
        <td>{{CompatGeckoMobile(10)}} {{property_prefix("moz")}}<br />
          {{CompatGeckoMobile(18)}}</td>
        <td>{{CompatUnknown}}</td>
        <td>12.10[*]</td>
        <td>{{CompatNo}}</td>
      </tr>
    </tbody>
  </table>
</div>
<p>[*] Doesn't fire the {{event("visibilitychange")}} event when the browser window is minimized, nor set <code>hidden</code> to <code>true</code>.</p>
<h2 id="See_also">See also</h2>
<ul>
  <li>Description of the <a href="http://blogs.msdn.com/b/ie/archive/2011/07/08/using-pc-hardware-more-efficiently-in-html5-new-web-performance-apis-part-2.aspx" title="http://blogs.msdn.com/b/ie/archive/2011/07/08/using-pc-hardware-more-efficiently-in-html5-new-web-performance-apis-part-2.aspx">Page Visibility API</a> on the IEBlog.</li>
  <li>Description of the <a href="http://code.google.com/chrome/whitepapers/pagevisibility.html" title="http://code.google.com/chrome/whitepapers/pagevisibility.html">Page Visibility API</a> by Google</li>
</ul>
Revert to this revision