List Virtual Screens in Puppeteer
Use Puppeteer’s Browser API to list screens, configure virtual monitors in headless Chromium, and distinguish screen topology from a page viewport.
To list the screens known to a Puppeteer browser, call await browser.screens(). It returns a ScreenInfo[] array. In headless Chromium, you can configure virtual screens at launch with --screen-info, or add and remove screens while the browser is running. Those configuration and mutation options are headless-only; in headful Chrome, the listing reflects the platform’s physical screens.
List the current screens
This runnable JavaScript example launches headless Chromium with two virtual screens, retrieves their information, and prints useful fields. It uses Puppeteer’s documented screen configuration approach.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
args: ['--screen-info={800x600 label=primary}{600x800 label=portrait}'],
});
try {
const screens = await browser.screens();
console.log(`Number of screens: ${screens.length}`);
for (const screen of screens) {
console.log({
id: screen.id,
label: screen.label,
left: screen.left,
top: screen.top,
width: screen.width,
height: screen.height,
isPrimary: screen.isPrimary,
isExtended: screen.isExtended,
orientation: screen.orientation,
});
}
} finally {
await browser.close();
}
Install Puppeteer in a project with npm install puppeteer, save this as an ES module such as list-screens.mjs, then run node list-screens.mjs. If using puppeteer-core, install that package and ensure a compatible Chrome or Chromium executable is available to launch.
The example configures an 800×600 primary screen and a 600×800 portrait screen. The returned screen objects describe the browser’s screen configuration; they do not create physical monitors.
Understand the ScreenInfo fields
Each item in the returned array is a ScreenInfo object. The documented fields are:
| Field | Meaning |
|---|---|
id |
Identifier for the screen, used when removing a screen. |
left, top |
Screen position in the screen layout. |
width, height |
Screen dimensions. |
availLeft, availTop |
Position of the available work area. |
availWidth, availHeight |
Dimensions of the available work area. |
label |
Screen label, if configured or supplied by the platform. |
isPrimary |
Whether the screen is primary. |
isExtended |
Whether the screen is an extended display. |
isInternal |
Whether the display is identified as internal. |
colorDepth |
Reported display color depth. |
devicePixelRatio |
Reported device pixel ratio. |
orientation |
Orientation information, including its type and angle. |
For a compact inventory, log the ID, label, bounds, dimensions, and primary/extended flags. Include orientation and device-pixel ratio when those properties are relevant to the test. Avoid assuming the returned ordering beyond what your test explicitly checks; identify a screen by its properties or ID.
Configure virtual screens in headless Chromium
Pass Chromium’s --screen-info switch in Puppeteer’s launch({args}). The documented syntax uses brace-delimited screen descriptions, for example:
const browser = await puppeteer.launch({
args: [
'--screen-info={800x600 label=primary}{600x800 label=portrait}',
],
});
const screens = await browser.screens();
In the documented headless setup, Chromium uses one 800×600 screen by default. If --window-size is specified without a screen configuration, the screen is as large as the requested window. Use --screen-info when the test needs a multi-screen layout or specific screen metadata.
The --screen-info switch configures virtual screens for headless Chromium. It does not alter the host computer’s display setup. Check the official Puppeteer screen configuration guide and the installed Puppeteer version’s API documentation when adapting the argument syntax.
Add and remove screens at runtime
Puppeteer can mutate the virtual screen layout while headless Chrome is running. browser.addScreen() returns the new screen’s information; pass its ID to browser.removeScreen() to remove it. Then query again to inspect the current layout.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
console.log('Initial screens:', (await browser.screens()).length);
const added = await browser.addScreen({
left: 800,
top: 0,
width: 600,
height: 800,
label: 'portrait',
});
console.log('Added screen:', added);
console.log('After adding:', (await browser.screens()).length);
await browser.removeScreen(added.id);
console.log('After removing:', (await browser.screens()).length);
} finally {
await browser.close();
}
These operations are headless-only. Removing the primary screen fails, so retain the ID returned for a secondary screen and remove that screen instead. Re-query with browser.screens() after a change rather than relying on a previously captured array.
Choose the right API: screens or viewport
A browser screen and a page viewport answer different questions. Use browser.screens() when the test concerns display topology: how many screens exist, their positions, dimensions, labels, or primary status. Use Page APIs when the test concerns the size or device metrics used to render a particular page.
| Need | Use |
|---|---|
| Inspect screen layout and metadata | await browser.screens() |
| Set one page’s viewport dimensions | await page.setViewport({ width, height }) |
| Apply a device profile | await page.emulate(device) |
Each page can have its own viewport. Puppeteer documents page.emulate(device) as a shortcut for setting the page’s user agent and viewport. Neither viewport setting nor device emulation configures multiple browser screens.
Headless and headful behavior
| Mode | browser.screens() |
Configure or mutate screens |
|---|---|---|
| Headless | Lists the browser’s screen configuration | Use --screen-info, browser.addScreen(), and browser.removeScreen() |
| Headful | Lists physical platform screens | The documented virtual screen configuration and add/remove operations are not supported |
If a test needs a predictable multi-screen topology, use headless mode and configure it explicitly. In headful mode, results depend on the screens available to the platform.
Troubleshooting
browser.screens is not a function
The installed Puppeteer version may not expose this API, or the value may not be a Puppeteer Browser instance. Check the installed package and its API documentation, then confirm that you are calling the method on the browser returned by puppeteer.launch().
The browser reports only one screen
Without --screen-info, the documented headless default is one 800×600 screen unless --window-size specifies another size. Pass the multi-screen argument when launching and inspect the result after launch.
--screen-info has no effect in headful mode
Virtual screen configuration with this switch is for headless Chromium. Headful Chrome reports physical platform screens; use headless mode for a configured virtual layout.
Adding or removing a screen fails
addScreen() and removeScreen() are headless-only. Also, the primary screen cannot be removed. In headful mode, inspect the platform screens without trying to mutate them; in headless mode, remove a secondary screen by the ID in its ScreenInfo.
The page size does not match the screen size
Screen dimensions describe the screen configuration, while page.setViewport() controls a page’s viewport. Set the viewport explicitly if the rendered page size is what the test needs.
Performance, reliability, and cost
Screen listing is a browser configuration query. For a reliable test, set the virtual topology at launch, read the screen list after launch, and assert only the properties the scenario depends on. When you add or remove a screen, query again before making assertions about the new state.
The documentation does not provide performance benchmarks or a quantified cost for screen enumeration. Puppeteer and Chromium run in your environment, so account for the resources and infrastructure used to launch and keep the browser running. A virtual screen configuration is useful for testing display topology; it does not replace a viewport setting when the goal is responsive page rendering.
Or skip the browser setup
If your goal is to capture a website image rather than test browser screen topology, ScreenshotNeo provides a website screenshot API. One GET request returns a PNG, JPEG, WebP, or PDF. The call below saves a capture as WebP; see the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card.
FAQ
Does browser.screens() create virtual displays?
No. It lists the browser’s current screen configuration. In headless mode, configure virtual screens at launch or add them at runtime; this does not create physical monitors.
Can I use screen listing in headful mode?
Yes. Puppeteer documents browser.screens() for headful mode, where Chrome uses physical platform screens. Virtual configuration and runtime screen changes are headless-only.
Can I remove the primary screen?
No. Removing the primary screen fails. Remove a secondary screen instead.
Should I use screen dimensions for responsive tests?
Usually, set the page viewport or emulate a device for page rendering tests. Use the Browser screen API when the behavior under test depends on screen topology.


