Headless Google Chrome: How to prevent sites to know whether their window is focused or not Headless Google Chrome: How to prevent sites to know whether their window is focused or not selenium selenium

Headless Google Chrome: How to prevent sites to know whether their window is focused or not


If your goal is to fool the visibility API, then inject this piece of script in the related page or frame:

await page.evaluate(`    Object.defineProperty(window.document,'hidden',{get:function(){return false;},configurable:true});    Object.defineProperty(window.document,'visibilityState',{get:function(){return 'visible';},configurable:true});    window.document.dispatchEvent(new Event('visibilitychange'));`);

It first overwrites window.hidden to make it return false. Then, it fires the visibilitychange event to notify the document in case the page is already hidden.

Or to override the API as soon as the document is created:

await page.evaluateOnNewDocument(`    Object.defineProperty(window.document,'hidden',{get:function(){return false;},configurable:true});    Object.defineProperty(window.document,'visibilityState',{get:function(){return 'visible';},configurable:true});`);


Page Visibility API

As per the documentation Page Visibility API comes handy when attempting to save resources and improving performance by letting a page avoid performing unnecessary tasks when the document isn't visible.

As per Page Visibility Level 2 W3C Editor's Draft:

The Page Visibility API defines a means to programmatically determine the visibility state of the top-level browsing context, and to be notified if the visibility state changes. Without knowing the visibility state of a page, web developers have been designing web pages as if they are always visible. This not only results in higher machine resource utilization, but it prevents web developers from making runtime decisions based on whether the web page is visible to the user. Designing web pages with knowledge of the page's visibility state can result in improved user experiences and power efficient sites.

With this API, web applications can choose to alter their behavior based on whether they are visible to the user or not. For example, this API can be used to scale back work when the page is no longer visible.


Visibility states

The Document of the top-level browsing context can be in either of the following visibility states:

  • hidden: The Document is not visible at all on any screen.
  • visible: The Document is at least partially visible on at least one screen.

The visibility states are reflected in the API via the VisibilityState enum as follows:

enum VisibilityState {  "hidden", "visible"};

Extensions

This specification extends the Document interface as follows:

partial interface Document {  readonly attribute boolean hidden;  readonly attribute VisibilityState visibilityState;  attribute EventHandler onvisibilitychange;};

An usage example

To improve the user experience and optimal CPU and power efficiency an application can autoplay a video when the application is visible, and automatically pause the playback when the application is hidden:

const videoElement = document.getElementById("videoElement");// Autoplay the video if application is visibleif (document.visibilityState === "visible") {  videoElement.play();}// Handle page visibility change eventsfunction handleVisibilityChange() {  if (document.visibilityState === "hidden") {    videoElement.pause();  } else {    videoElement.play();  }}document.addEventListener('visibilitychange', handleVisibilityChange);

Further, @MichaelMahemoff in this blog further states that, Multi-tab browsing being the current norm now, you can't assume the user is watching your app just because it's running and the new Page Visibility API lets your app discover if it's visible or not. You could use the API to cut down on unnecessary network activity and computation. If you are using any of the current Chrome or Chromium build you can try out in the console if the current page is hidden through document.webkitHidden. However, document.webkitVisibilityState will return a string indicating the current state, one of visible, hidden, and prerendered. A new webkitvisibilitychange event will fire when any of these changes, e.g. when the user opens you app's tab, or moves away from it.


Solution

All these interactions can be observed using the visibility.js which is a wrapper for the Page Visibility API and allows you to determine whether your web page is either visible to a user or hidden in background tab or prerendering. It also allows you to use the page visibility state in JavaScript logic and improve browser performance by disabling unnecessary timers and AJAX requests, or improve user interface experience (for example, by stopping video playback or slideshow when user switches to another browser tab).

Firefox specific solution: An alternative Firefox specific solution can be to use the Disable Page Visibility API extension for Firefox which disables the API for all pages.

Here you can find a detailed discussion on How to install extension permanently in geckodriver

Chrome specific solution: An alternative Chrome specific solution can be to use the Don't Make Me Watch extension from the Chrome Web Store.

Here you can find a detailed discussion on How to load extension within chrome driver in selenium with python