Home | Send Feedback

A look at the Page Visibility API

Published: July 29, 2019  •  javascript

The Page Visibility API is a browser-based interface that tells your JavaScript application if the page is visible to the user or in the background.

The API is very simple and provides an event (visibilitychange) and two properties that are accessible via document object (document.hidden and document.visibilityState).

The API is widely supported in all major browsers (even IE10 and IE11):
https://caniuse.com/#feat=pagevisibility

The Page Visibility API is especially useful for saving resources and improving performance by letting a page avoid performing unnecessary tasks when the document isn't visible. When the user minimizes the browser or switches to another tab, the API emits the visibilitychange event. The same event is emitted when the user restores the browser from the minimized state or changes to the tab where your application is running.

Depending on the visibility state, your application can perform some actions or behave differently. If your application plays a video or music, it can automatically pause the video or music when the user puts the tab into the background, and resume when the user returns to the tab. Another use case is to stop sending poll requests to a server when the page is in the background. Your application could suspend a WebSocket or EventSource connection and resume if the application is visible again, to save resources. Especially useful on mobile browsers where you have limited battery life and maybe limited data bandwidth and it would make no sense to update a website if it's not visible.

The following example listens for a change in visibility, changes the title of the page, and sends a request to a Spring Boot back end. This allows us to observe when the visibilitychange event is emitted.

document.addEventListener('visibilitychange', () => handleVisibility());

function handleVisibility() {
  if (document.visibilityState === 'hidden') {
    document.title = 'Visibility: hidden';
    fetch('http://localhost:8080/hidden');
  } else if (document.visibilityState === 'visible') {
    document.title = 'Visibility: visible';
    fetch('http://localhost:8080/visible');
  }
}

handleVisibility();

main.js

If you open the application in two tabs, you see that in the active tab the property document.visibilityState is set to the value visible and in the inactive tab to hidden.

visibilitychange

On a desktop browser, the event is emitted when you minimize and restore the browser. On a mobile browser, it is emitted when you press the home button and bring back the browser from the background, and it is also emitted when you press the power button to turn off the screen or to turn it on, while the browser is the active application.

The document.visibilityState property supports two additional values prerender and unload.

Notice that both values are not supported in all browsers. The prerender state could be useful for web site analytics libraries to exclude these pages from the page visit counter. When a page is in the prerender state, the browser rendered the page only internally and is not visible to the user.

Visibility.js

When you use the Page Visibility API a lot in your application, you should take a look at the Visibility.js library. It's a wrapper library that simplifies common tasks working with the Page Visibility API.

You add the library with npm install visibilityjs to a npm managed JavaScript project.

The library provides several methods that are accessible from the Visibility object.

The onVisible() method checks the current visibility state of the page. If the page is visible, it will run the callback; otherwise, the method waits until the visibility state changes to visible and then runs the callback. Notice that the callback is only executed once, even when the state changes multiple times from visible to hidden and back. Only the first time the page becomes visible, the callback method is executed.

Visibility.onVisible(() => {
  console.log('onVisible event');
  document.title = 'Visibility.js (visible)';
});

main.js

Next convenience method we take a look at is every(). It allows you to execute a callback periodically, but only when the page is visible.

This example prints out a text every second into the console, but only when the page is visible. As soon as you change the tab or minimize the browser every() stops and resumes when the state changes back to visible.

Visibility.every(1000, () => console.log('every 1000ms'));

every() also supports a second interval parameter which will be used when the page is hidden. In the next example, a GET request is issued every 15 seconds when the page is visible, and every 1 minute when the page is hidden.

Visibility.every(15 * 1000, 60 * 1000, s => fetch('http://localhost:8080/poll'));

main.js


every() returns an identifier that can be used for stopping the timer. To cancel the timer pass the identifier to the stop() method.

const everyTimer = Visibility.every(1000, () => console.log('every 1000ms'));
setTimeout(() => Visibility.stop(everyTimer), 5000);

main.js


Another method is change() which will install a listener function that is called each time the visibility state changes.

Visibility.change((e, state) => {
  console.log('change event', state);
  updateTitle();
});

updateTitle();

function updateTitle() {
  if (Visibility.hidden()) {
    document.title = 'Visibility.js (hidden)';
  } else {
    document.title = 'Visibility.js (visible)';
  }
}

main.js

Visibility.hidden() returns false when the visibility state is visible and returns true when the state is either hidden or prerender.

Visibility.state() returns a string with the current visibility state. This method returns the same string values as document.visibilityState.


This was just a quick overview of the Visibility.js library.
For a detailed description check out the project page: https://github.com/ai/visibilityjs


This concludes our tour around the Page Visibility API. A simple browser-based interface that is supported in all modern browsers and gives your application access to the visibility state of your page.

You find the source code of all the presented examples on GitHub:
https://github.com/ralscha/blog2019/tree/master/visibility