Page Visibility API in JavaScript and HTML5

- 👤 Andrés Cruz

🇪🇸 En español

Page Visibility API in JavaScript and HTML5

View Example

The Page Visibility API is one of those unflashy, yet extremely useful functionalities. In my case, I used it to prevent certain animations from consuming CPU when the user switched tabs. Since then, I consider it essential in any project involving timers, multimedia, or frequent server requests.

For example, I use it on the Academia website for the book viewer; when the user LEAVES the tab for another, I take the opportunity to save the state.

In this guide, I'll explain what it is, how it works, and how to implement it with practical examples based on my own experience.

The Page Visibility API allows you to know when a web page is being viewed by the user, and therefore, we can make configurations to avoid the use of unnecessary resources once the user is not visiting the page in question; the following image indicates which pages are being viewed and which are not:

Visible page

That is, when the user moves to another tab or minimizes the window, an event called visibilitychange is triggered to indicate that the page is not being viewed (hidden); this can be quite useful for customizing sections of the web page; for example, the one presented by MDN.

In this post, we will explain how to use the Page Visibility API, which is one of the other JavaScript APIs we've covered in DesarrolloLibre:

What the Page Visibility API is and what it's for

The Page Visibility API allows you to know if your page is:

  • visible
  • partially visible
  • hidden
  • or rendering in the background

This information allows you to optimize resources, improve performance, and avoid unnecessary behaviors when the user isn't viewing your page.

How the visibility change works

Every time the user:

  • changes tabs
  • minimizes the window
  • locks the device
  • or opens another window on top

…the browser fires the visibilitychange event.

When I first tested this API, I confirmed something curious: the event is not fired when the window loses focus, only when the page truly stops being visible.

Differences between document.hidden and visibilityState

  • Property    Type    What it indicates
  • document.hidden    boolean    true if the page is hidden
  • document.visibilityState    string    visible / hidden / prerender / unloaded

When to use this API: real optimization cases

This API is ideal in any workflow where you want to save resources without breaking the browser's logic or the user experience.

Pause animations, carousels, or video

In one of my projects, I paused an image carousel. Without this API, the carousel continued advancing even when the user had the tab hidden, wasting CPU.

Reduce server requests when the user is away

If your page queries an endpoint every X seconds, you can:

  • pause the requests when it is hidden
  • resume them when it becomes visible again

This reduces the load on your backend and improves the experience.

Improve mobile battery consumption

Google emphasizes this: the API helps extend battery life on mobile devices by stopping processes that are not on screen.

In my case, I noticed that on older phones, some animations notably reduced battery life if they weren't paused.

The Page Visibility API in practice: available properties and states

In this part, we will introduce the use of the API by explaining its main components.

The visibilityState enum type can return:

  • visible: the page is on screen
  • hidden: completely hidden
  • prerender: the browser preloads the document
  • unloaded: state prior to document unload

Prefixes and current compatibility

Nowadays, prefixes are hardly used, except in older Android browsers.

But for legacy projects, here's the correct way to detect them:

function getHiddenProperty(prefix) {
 return prefix ? prefix + 'Hidden' : 'hidden';
}

Accessing the Page Visibility API in JavaScript

The document.hidden property allows access to the Page Visibility API; however, due to the large number of browsers and their versions, some may not support this API or it may be necessary to use prefixes:

document.addEventListener('visibilitychange', () => {
 if (document.hidden) {
   console.log('La página está oculta.');
 } else {
   console.log('La página es visible.');
 }
});

The following function allows you to verify if the browser supports the Page Visibility API and obtain its prefix if it requires one; it can be easily adapted for any of the JavaScript APIs:

function getPrefix() {
		// check if the browser supports the default prefix if
		if ('hidden' in document) 
			return NULL;
		
		// other possible prefixes var 
		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]; // retornamos el prefijo
		}
		// not support
		return NULL;
	}

Once we have the browser's prefix to access the API, we can gain access to the property in question using the following function which receives the previously obtained prefix as a parameter:

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

Page Visibility API Events

Using the prefix obtained in the previously defined function again, we get the visibilitychange event in its variation dependent on the browser used:

	// Get the prefix to access the visibilitychange event 
	function getVisibilityEvent(prefix) {
		if (prefix) {
			return prefix + 'visibilitychange';
		} else {
			return 'visibilitychange';
		}
	}

Applied example with business logic

In one of my projects:

  • It paused a video
  • It stopped a timer
  • It saved the last visible state
document.addEventListener('visibilitychange', () => {
 if (document.visibilityState === "hidden") {
   pauseVideo();
   stopTimer();
 } else {
   resumeVideo();
   startTimer();
 }
});

You can see a final example that puts everything discussed so far into practice:

View Example

Frequently Asked Questions (FAQ)

  • Are document.hidden and visibilityState the same?
    • No. One is boolean, the other returns a more specific state.
  • Does the visibilitychange event work on mobile?
    • Yes, and in many cases it is even more useful than on desktop.
  • Are prefixes still needed?
    • Only on very old Android browsers.
  • What tasks should I pause when the page is hidden?
    • Animations, timers, videos, recurrent requests.
  • Can this API be disabled?
    • Not in a standard way; some browsers may limit information for privacy.

Conclusion

Although not as flashy as WebGL or WebAudio, the Page Visibility API fulfills an essential role: preventing our pages from consuming unnecessary resources when no one is viewing them.

  • In my own projects, it has allowed me to:
  • save CPU
  • extend battery life on mobile devices
  • avoid unnecessary server calls
  • improve the user experience

It is simple, stable, and supported practically by all modern browsers.

I agree to receive announcements of interest about this Blog.

The Page Visibility API allows us to know when a web page is being viewed by the user and therefore we can make configurations to avoid the use of unnecessary resources.

| 👤 Andrés Cruz

🇪🇸 En español