LearnAn Introduction to The Page Visibility API

Matt West
writes on September 19, 2013

Share with your friends


The days of browsing the web using a single window (or tab) are long gone. Most of us now browse with multiple windows and/or tabs open at the same time. As developers we have never had a way of telling whether our web page is visible to the user or if it’s buried away amongst a stack of inactive tabs. This is all changing due to the introduction of the Page Visibility API.

The Page Visibility API gives developers a way of checking to see if their web page is visible to the user. The API also includes an event that gives developers the ability to easily write code that will be executed when the page’s visibility changes.

In this blog post you are going to learn how to use the Page Visibility API to pause a video when a web page is hidden, and then resume playback when the page becomes visible again.

Lets get started by taking a look at how the API works.

Checking The Page Visibility

The Page Visibility API adds two new properties to the document interface:

  • document.hidden
  • document.visibilityState

The new hidden property is a boolean that is set to true if the page is hidden and false if it’s visible.

The visibilityState property is a string that describes the current state of the page. It can be one of the following:

  • hidden – The page is not visible on any screen.
  • visible – The page is visible to the user.
  • prerender – The page has been loaded off-screen and is not visible.
  • unloaded – The page is going to be unloaded (the user is navigating away from this page).

Note: These properties are still vendor prefixed in Chrome and Opera. Firefox removed the vendor prefix in version 17. To be safe, make sure that you check to see if a vendor prefix is required before using these properties in your code. We will see an example of how to do this later in the demo.

Listening For Changes in Visibility State

In addition to the new document properties the Page Visibility API also introduces the visibilitychange event. This event is fired on document when the user shows or hides the window/tab.

document.addEventListener('visibilitychange', function(event) {
  if (document.hidden) {
    // The page is hidden.
  } else {
    // The page is visible.

Note: This event is also vendor-prefixed in some browsers. Take a look at the demo application to see how to check for prefixes.

Demo: Pausing a Video When The Window is Hidden

Page Visibility API Demo

Page Visibility API Demo

See the Demo Download The Code View on CodePen

Now that you understand how to use the Page Visibility API lets take a look at an example.

In this section we are going to create a demo application that uses the Page Visibility API to pause a video when the page is hidden, and then start it back up when the page becomes visible again.

First we need to setup the HTML markup for our demo. We’re going to be using the <video> element so that we can easily control the playback of the video.

The stylesheet and videos used in this demo can be found in the code resources.

<!DOCTYPE html>
<html lang="en">
  <meta charset="utf-8">
  <title>PageVisibility API Demo</title>

  <link rel="stylesheet" href="style.css">
  <div id="page-wrapper">

    <h1>PageVisibility API Demo</h1>

    <video id="video" width="640" height="365" controls>
      <source src="videos/mikethefrog.webm" type="video/webm">
      <source src="videos/mikethefrog.ogv" type="video/ogv">
      <source src="videos/mikethefrog.mp4" type="video/mp4">
        Your browser doesn't support HTML5 video.
        <a href="videos/mikethefrog.mp4">Download</a> the video instead.


  <script src="app.js"></script>

Now that we’ve got the HTML setup we need to start writing the JavaScript that will monitor the page visibility. Create a new file called app.js.

To get started we need to write a bit of code that will determine whether to use vendor prefixes. This getPrefix() function checks to see if the hidden property is present on document. If it is, we don’t need to use vendor prefixes so we can return null. If hidden is not present we need to loop through all of the possible vendor prefixes until we find the property. Once we’ve found the prefix we simply return the prefix string. If we get to the end of the function without finding the prefix the API must not be supported so we just return null.

// Get the prefix for this browser.
function getPrefix() {
  // Check to see if the browser supports the unprefixed property.
  if ('hidden' in document) {
    // No prefix needed, return null.
    return null;

  // Loop through all the possible prefixes.
  var prefixes = ['moz', 'ms', 'o', 'webkit'];

  for (var i = 0; i < prefixes.length; i++) {
    var testPrefix = prefixes[i] + 'Hidden';
    if (testPrefix in document) {
      return prefixes[i];

  // The API must not be supported in this browser.
  return null;

Next we need to write a few helper functions that will generate the correct property and event names based on the prefix that is returned by getPrefix().

Note: We won’t be using the document.visibilityState property in this demo but I’ve included a helper function here just in case you need it in the future.

// Prefix the hidden property.
function getHiddenProperty(prefix) {
  if (prefix) {
    return prefix + 'Hidden';
  } else {
    return 'hidden';

// Prefix the visbilityState property.
function getVisibilityStateProperty(prefix) {
  if (prefix) {
    return prefix + 'VisibilityState';
  } else {
    return 'visibilityState';

// Prefix the visibilitychange event.
function getVisibilityEvent(prefix) {
  if (prefix) {
    return prefix + 'visibilitychange';
  } else {
    return 'visibilitychange';

Okay, so now that we’ve got cross-browser compatibility covered we can start writing the main code for our application.

In the first section we call the getPrefix() function to find out if we need to use a vendor prefix in our code. We then create variables called hidden and visibilityChangeEvent and initialize these using the helper methods we wrote earlier. We also create a variable called wasPlaying and set it’s value to false. This will be used as a way of remembering whether the video was playing when the page lost visibility.

Next we get a reference to our video and store this in a variable called video.

Finally we setup an event listener that will be executed when the visibilitychange event is fired. We use the visibilityChangeEvent variable we created earlier to make sure that the correct vendor-prefixed version is being used (if required).

// The cross browser compatibility code.

window.onload = function() {
  // Get the prefix for this browser.  
  var prefix = getPrefix();

  // Prefix the document properties/events we will be using.
  var hidden = getHiddenProperty(prefix);
  var visibilityChangeEvent = getVisibilityEvent(prefix);

  // Variable to track if the video was playing when the page visibility changed.
  var wasPlaying = false;

  // Get a reference to the video.
  var video = document.getElementById('video');

  // Listen for the visibilitychange event.
  document.addEventListener(visibilityChangeEvent, function(e) {



Now it’s time to write the code that will handle pausing and playing the video.

First we check to see if the page is visible or hidden. If the page is hidden we also need to check if the video is playing or not. When the video is playing we need to set the wasPlaying variable to true and pause the video. If the video was paused to begin with we just make sure that wasPlaying is set to false.

If the page is visible we need to check if the video was playing before the page became hidden. We do this using the wasPlaying variable. If the value of wasPlaying is true we call video.play() to resume playback.

// If the document is hidden we want to pause the video.
if (document[hidden]) {
  // Check to see if the video is playing
  if (video.paused == false) {
    // Set the wasPlaying flag to true.
    wasPlaying = true;

    // Pause the video.
  } else {
    // Make sure the wasPlaying is set to false if the video was paused.
    wasPlaying = false;
} else {
  // If the video was playing before we lost visibility, restart it.
  if (wasPlaying) {
    // Play the video.

That’s all the code that we need for this example. Load up the live demo and see it in action.

Browser Support For The Page Visibility API

Support for the Page Visibility API is a recent addition in IE10. Chrome and Firefox have included support for a while. However current versions of Chrome and Opera require the webkit prefix. Firefox 17 and below require the moz prefix. Safari is said to be introducing support for the Page Visibility API in version 7.

IE Firefox Chrome Safari Opera
10+ 10.0+ 14.0+ 7.0+ 12.1+

Source: http://caniuse.com/#feat=pagevisibility

Final Thoughts

Up until the introduction of the Page Visibility API developers have only had to consider how their websites act when they are visible. This has all changed now. We now need to be thinking about how we can make our websites better citizens of the browser.

There are a whole bunch of things that websites do that become irrelevant if the user can’t see the page. Animations is the first example that springs to mind. Browsers already have some native functionality that helps to recover resources from inactive pages, but we can help to make things even better by being responsible with how our websites behave when hidden.

19 Responses to “An Introduction to The Page Visibility API”

  1. Interesting functionality with potential to create useful websites behaviours.

  2. Cyvvilek Maciek on September 19, 2013 at 6:21 pm said:

    Jeeeez….! ‘visibilitychange’ doesn’t use bloody camelcase….
    Took me some time to figure out…
    Very nice post :) thanks

    • Hi Cyvvilek!

      Events tend to be named in all lowercase.
      I can see how the `visibilityChangeEvent ` variable in the demo could cause some confusion though. Sorry about that.

      Thanks for reading :)

  3. HemanthMalli on September 20, 2013 at 8:45 am said:

    Good insights on the functionality of page visibility API for making websites better for the browser!!

  4. Athena Digital Media on September 21, 2013 at 12:07 am said:

    Very interesting article thanks

  5. Dipesh Bhardwaj on September 23, 2013 at 1:28 am said:

    Really great post. I am always wondering what is behind such behaviors in website also in Google image search and see here is the answer Page Visibility API

  6. [url=http://www.ooowatch.com/tokei/vuitton/index.html]ブランドコピー時計大人気を海外激安通販専門店ロレックス、ブルガリ、フランク ミュラー、シャネル、カルティエ、オメガ、IWC、ルイヴィトン、オーデマ ピゲ、ブライトリング、グッチ、エルメス、パネライ、パテックフィリップ偽物(コピー商品)のブランドの腕時計の販売、通販。[/url]

  7. [url=http://www.bagkakaku.com/louisvuitton_bag.html]ブランドコピー時計大人気を海外激安通販専門店ロレックス、ブルガリ、フランク ミュラー、シャネル、カルティエ、オメガ、IWC、ルイヴィトン、オーデマ ピゲ、ブライトリング、グッチ、エルメス、パネライ、パテックフィリップ偽物(コピー商品)のブランドの腕時計の販売、通販。[/url]

  8. [url=http://www.msnbrand.com/brand-copy-IP-12.html]高品質2015シャネル スーパーコピー激安專門店弊社は海外大好評を博くシャネル コピー激安老舗です,2015高品質シャネル バッグ コピー,シャネル 靴 コピー,シャネル 財布 コピー品の品質はよくて、激安の大特価でご提供します。[/url]

  9. [url=http://www.brandiwc.com/brand-37-copy-0.html]BVLGARI(バッグ?財布?小物)CHLOE(バッグ?財布、小物)偽物ブランド,激安,コピー?ルイヴィトンバッグ,偽物?ルイヴィトン財布,コピーバッグ,ブランドバッグ,偽物バッグ,偽物シャネルバッグ,偽物エルメスバッグ,偽物グッチバッグ,偽物財布,コピー財布,時計の專門店[/url]

  10. [url=http://www.wtobrand.com/otyd1.html]ブランドコピー時計大人気を海外激安通販専門店ロレックス、ブルガリ、フランク ミュラー、シャネル、カルティエ、オメガ、IWC、ルイヴィトン、オーデマ ピゲ、ブライトリング、グッチ、エルメス、パネライ、パテックフィリップ偽物(コピー商品)のブランドの腕時計の販売、通販。[/url]

  11. [url=http://www.bagkakaku.com/celine_bag.html]ロレックスコピー販売、代引きロレックス時計コピー通販、全て新品、高い品質、激安、送料無料。ロレックス時計コピーなど世界中有名なブランドレプリカを格安で通販しております。N級品スーパーコピーブランドは 業界で最高な品質に挑戦しますロレックコピー,ロレックコピー代引き,ロレック激安,ロレックス偽物 ,最高級ロレックコピーロレックス時計コピー,フェラーリコピー時計,パネライコピー時計,パテックフィリップコピー時計,ヴァシュロン.コンスタンタンコピー時計,エルメスコピー時計,カルティエコピー時計ルイヴィトンコピー、 ロレックスコピー、シャネルコピー、グッチコピー、エルメスコピー、 ボッテガヴェネタコピー、 バーバリーコピー、ミュウミュウコピー、トリーバーチコピー、バレンシアガコピー、ディオールコピー、ブルガリコピー、ブラダコピー、 ドルチェ&ガッバーナコピー、オメガコピー、フランク ミュラーコピー、gagaコピー。古驰拷贝, 靴/サンダル,サングラスコピー欧米O級品オーダー服各種のブランドの服、靴、、財布、腕時計の複製品をかばん一番ブランドliveブランドコピー服,ブランドバッグコピー,ブランド時計,ブランド靴シリーズ欧米O級品コーナーラッピング用品[/url]

  12. [url=http://www.gginza.com/bag/chanel/index.html]人気スーパーコピーブランド時計激安通販専門店私達は長年の実体商店の販売経験を持って、先進とプロの技術を持って、高品質のスーパーコピー時計づくりに 取り組んでいます。最高品質のロレックス時計コピー、カルティエ時計コピー、IWC時計コピー、ブライトリング時計コピー、パネライ時計コピー激安販売中商品の数量は多い、品質はよい。海外直営店直接買い付け!★ 2015年注文割引開催中,全部の商品割引10% ★ 在庫情報随時更新! ★ 実物写真、付属品を完備する。 ★ 100%を厳守する。 ★ 送料は無料です(日本全国)!★ お客さんたちも大好評です★ 経営方針: 品質を重視、納期も厳守、信用第一!税関の没収する商品は再度無料にして発送します[/url]

  13. [url=http://www.brandiwc.com/brand-2-copy-0.html]弊社は海外安心と信頼のプラダ 時計 コピーです。2015 新作が満載!皆様を歓迎して当店をご光臨賜ります。ロレックス時計コピー,パネライ時計コピー,ウブロ時計コピー ,ブライトリング時計コピー,IWC時計コピー,フランクミュラー時 計コピー,ショパール時計コピー,フェラーリ時計コピー,グラハム 時計コピー,ハリー ウィンストン時計コピー等。サイトは世界一流ブランド コピー 専門店です。ぜひ一度当店の商品をお試しください。驚きと満足を保証致します。ご利用をお待ちしております。[/url]

Leave a Reply

Want to learn more about Javascript?

Learn how to use JavaScript to add interactivity to websites.

Learn more