Understanding the visibilitychange Event in Modern Web Development

Learn how to leverage the Page Visibility API to build performant, battery-efficient web applications that respond intelligently when users switch tabs or minimize their browser.

What is the visibilitychange Event?

The visibilitychange event is a DOM event that fires at the document when the contents of its tab have become visible or have been hidden. This event is part of the Page Visibility API, a web standard that enables developers to detect when a webpage is visible to the user and respond accordingly.

The Page Visibility API performs a simple but important function--it lets your application know when a page is visible to the user. This basic piece of information enables the creation of web pages that behave differently when they are not being viewed.

Key characteristics:

  • The event is fired at the document, not the window
  • It indicates the tab's visibility state has changed
  • Part of the W3C Page Visibility specification
  • Supported across all modern browsers since 2015-2021
  • Not cancelable

As part of modern web development best practices, properly handling visibility changes helps create applications that respect user attention and system resources.

Basic visibilitychange Event Listener
1// Simple visibility change handler2document.addEventListener('visibilitychange', () => {3 if (document.hidden) {4 console.log('Page is hidden');5 // Perform hidden state actions6 } else {7 console.log('Page is visible');8 // Perform visible state actions9 }10});11 12// Using visibilityState property13function getVisibilityState() {14 switch (document.visibilityState) {15 case 'visible':16 return 'Page is fully visible';17 case 'hidden':18 return 'Page is hidden';19 default:20 return 'Unknown state';21 }22}

Understanding Visibility States

The Page Visibility API provides two properties for checking the current visibility state:

document.hidden Property

The document.hidden property returns true if the page is in a state considered to be hidden to the user, and false otherwise. This is the simplest way to check if your page is currently visible.

When a page is considered hidden:

  • The user has minimized the browser window
  • The page is on a background tab
  • The browser is partially obscured by another window
  • The device's screen is turned off (mobile)
  • The user has switched to a different application (mobile)

document.visibilityState Property

The document.visibilityState property provides more granular information:

ValueDescription
visibleThe page content is at least partially visible (foreground tab of a non-minimized window)
hiddenThe page's content is not visible to the user

Understanding these states is essential for building performant JavaScript applications that respond intelligently to user behavior.

Practical Use Cases

The visibilitychange event enables a wide range of practical optimizations for web applications:

Pausing Media Playback

One of the most common uses is pausing media when the user leaves the tab:

let video = document.querySelector('video');
let wasPlaying = false;

document.addEventListener('visibilitychange', () => {
 if (document.hidden) {
 wasPlaying = !video.paused;
 video.pause();
 } else if (wasPlaying) {
 video.play();
 }
});

Analytics and Session Tracking

The transition to "hidden" is reliably the last event before a user potentially leaves your page:

document.onvisibilitychange = () => {
 if (document.visibilityState === 'hidden') {
 navigator.sendBeacon('/api/analytics/session-end', JSON.stringify({
 sessionDuration: Date.now() - sessionStartTime,
 pagePath: window.location.pathname
 }));
 }
};

Reducing Polling and API Calls

Optimize network traffic by adjusting polling frequency:

document.addEventListener('visibilitychange', () => {
 if (document.hidden) {
 // Reduce polling frequency when hidden
 clearInterval(pollInterval);
 pollInterval = setInterval(fetchCriticalUpdates, 60000);
 } else {
 clearInterval(pollInterval);
 pollInterval = setInterval(fetchUpdates, 5000);
 }
});

Animation Performance

Pause animations when they're not visible to save resources:

document.addEventListener('visibilitychange', () => {
 const animatedElements = document.querySelectorAll('.animated');
 animatedElements.forEach(el => {
 el.style.animationPlayState = document.hidden ? 'paused' : 'running';
 });
});

These patterns are essential for building performant web applications that conserve resources and respect user attention.

Performance Implications and Browser Behavior

Understanding how browsers handle background tabs helps set realistic expectations.

Browser Throttling Behavior

Modern browsers automatically throttle background tabs:

  • requestAnimationFrame: Stopped in background tabs to improve performance and battery life
  • setTimeout/setInterval: Throttled with increased minimum delays (up to 1000ms in many browsers)
  • Budget-based throttling: Timer tasks only run when budget is non-negative; budget regenerates ~10ms/second

Processes Exempt from Throttling

Some operations continue running:

  • Audio-playing tabs: Not throttled (hence the importance of manual pausing)
  • WebSockets/WebRTC: Unthrottled to prevent connection timeouts
  • IndexedDB operations: Left unthrottled to prevent timeouts

While automatic throttling helps, explicitly using visibilitychange provides more control over resource management. This approach is a key aspect of optimizing web performance for modern applications.

Best Practices for Modern Web Development

Recommended Patterns

  • Always clean up resources when hidden: Pause timers, animations, and API polling
  • Use sendBeacon for analytics: Reliable even when the page is unloading
  • Preserve user state: Save unsaved input when the page becomes hidden
  • Resume gracefully: Stagger resumption to prevent resource spikes

Common Mistakes to Avoid

  • Don't rely solely on focus/blur: Window focus ≠ page visibility
  • Don't assume immediate resumption: Browsers may delay full performance restoration
  • Don't use for authentication: Not a reliable user presence indicator
  • Don't over-optimize trivial operations: Consider the overhead vs. benefit

React/Next.js Integration

function usePageVisibility() {
 const [isVisible, setIsVisible] = useState(!document.hidden);

 useEffect(() => {
 const handleVisibilityChange = () => {
 setIsVisible(!document.hidden);
 };
 document.addEventListener('visibilitychange', handleVisibilityChange);
 return () => {
 document.removeEventListener('visibilitychange', handleVisibilityChange);
 };
 }, []);

 return isVisible;
}

This custom hook can be used in any React or Next.js application to add visibility awareness with proper cleanup.

Browser Compatibility

The Page Visibility API is a well-established web standard:

BrowserVersionStatus
Chrome33+Full support
Firefox18+Full support
Safari7+Full support
Edge12+Full support
MobileAll modernSupported

The API is considered Baseline Widely Available--you can rely on it across all modern browsers without vendor prefix fallbacks for most use cases.

For cross-browser compatibility in legacy scenarios, you can detect prefixed versions, though this is rarely needed in modern web development.

Build Performant Web Applications

Our team specializes in building modern web applications that leverage web APIs for optimal performance and user experience.

Frequently Asked Questions

What is the difference between visibilitychange and beforeunload?

The visibilitychange event fires whenever the tab becomes visible or hidden, while beforeunload only fires when the page is about to be unloaded. visibilitychange is more reliable for session tracking and can be used for analytics without blocking page navigation.

Does visibilitychange work on mobile devices?

Yes, visibilitychange works on mobile browsers. It fires when the user switches to a different app, when the browser is backgrounded, or when the device's screen is turned off.

Should I still use visibilitychange if browsers throttle background tabs?

Yes. While browsers throttle many operations automatically, explicit visibilitychange handling gives you more control. You can make more aggressive optimizations, save state more reliably, and provide better user experiences.

How does visibilitychange affect SEO?

visibilitychange itself doesn't directly affect SEO. However, using it to improve page performance (faster loading, less resource consumption) can contribute to better Core Web Vitals scores, which are ranking factors.