Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
Redmond desk7 min

How to Manage Browser Windows with Puppeteer

Puppeteer separates native browser windows from pages and viewports. Learn which API to use for sizing, maximizing, listing tabs, and isolating sessions.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In Puppeteer, a Page represents a tab-like page, a viewport is the area where that page renders content, and a native browser window has its own position, outer dimensions, and state. Use Browser.setWindowBounds() to move or maximize a native window, Page.resize() to request a content-area size, and Page.setViewport() to control viewport dimensions or emulate a device. These controls solve different problems, so choose based on what you need to measure or change.

The examples below follow the Puppeteer API documented in versions 25.9.0 and 25.12.0. Check the version installed in your project because APIs can evolve.

As an Amazon Associate I earn from qualifying purchases.

Choose the Puppeteer API for the change you need

Goal API What it controls Important detail
Move, maximize, restore, or inspect a native browser window Browser.getWindowBounds() and Browser.setWindowBounds() Window position, bounds, and state Use the window ID for the relevant window; create a window-type page where needed. Puppeteer Window management.
Request a specific content-area size Page.resize() Browser window size derived from desired content dimensions A default viewport may constrain the window; clear it if appropriate and wait for the resize event. Puppeteer Window management.
Set a responsive layout or device-like viewport Page.setViewport() The page viewport It does not set native window bounds. Changing isMobile or hasTouch can reload the page. Page.setViewport().
Keep sessions separate Browser.createBrowserContext() and its pages Page grouping and isolated storage Popups belong to their opener’s context; closing a context closes its pages. BrowserContext.

Launch a browser and open pages

A browser can have multiple Page instances. Open a browser and create a page with newPage() for a straightforward tab-like page:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    console.log(await page.title());
  } finally {
    await browser.close();
  }
})();

Set headless: false when you need to see or interact with a visible browser window. For a task that only needs page rendering and does not need native window interaction, use the launch behavior appropriate to your installed Puppeteer version and environment.

How do I resize a Puppeteer browser window?

Set native window position, bounds, or state

Puppeteer’s window-management guide directs users to Browser.getWindowBounds() and Browser.setWindowBounds() for native window position and state. Create a page of type window, get its window ID, then inspect or change that window:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  try {
    const page = await browser.newPage({ type: 'window' });
    const windowId = await page.windowId();

    const bounds = await browser.getWindowBounds(windowId);
    console.log('Current window bounds:', bounds);

    await browser.setWindowBounds(windowId, { windowState: 'maximized' });
    // Do work in the maximized window.
    await browser.setWindowBounds(windowId, { windowState: 'normal' });
  } finally {
    await browser.close();
  }
})();

To set ordinary bounds, pass the desired position and dimensions in the bounds object supported by your installed Puppeteer version. The window ID identifies which window to control; do not assume the page viewport dimensions are equivalent to its outer window dimensions.

Request a specific content area

Use Page.resize({contentWidth, contentHeight}) when the required measurement is the page’s content area rather than a device-emulated viewport. A default viewport can constrain the window, so clear it first if that is interfering. The resize is asynchronous; wait for the resize event before reading dimensions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  try {
    const page = await browser.newPage({ type: 'window' });
    await page.setViewport(null);

    await page.evaluate(() => new Promise(resolve => {
      window.addEventListener('resize', resolve, { once: true });
    }));
    await page.resize({ contentWidth: 600, contentHeight: 400 });

    const dimensions = await page.evaluate(() => ({
      innerWidth: window.innerWidth,
      innerHeight: window.innerHeight,
      outerWidth: window.outerWidth,
      outerHeight: window.outerHeight
    }));
    console.log(dimensions);
  } finally {
    await browser.close();
  }
})();

For a resize listener that is guaranteed to be installed before the resize request, register it in Node before calling resize():

const resized = page.evaluate(() => new Promise(resolve => {
  window.addEventListener('resize', resolve, { once: true });
}));
await page.resize({ contentWidth: 600, contentHeight: 400 });
await resized;

Browser chrome adds to the outer dimensions, so requesting a 600×400 content area does not mean a 600×400 outer window. Puppeteer’s guide shows an example environment where an inner size of 600×400 corresponded to an outer size of 600×487; that is an example, not a universal chrome-size constant. Window management guide.

When should I use Page.setViewport()?

Use Page.setViewport() when the task is about the page’s rendering area, responsive breakpoints, or device emulation—not moving or resizing the native browser window. Set it before navigation when possible so the page initially loads at the intended viewport.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1280, height: 800 });
    await page.goto('https://example.com');
  } finally {
    await browser.close();
  }
})();

Viewport settings can be configured separately for each page. Be aware that changing isMobile or hasTouch can reload the page. See the Page.setViewport API reference for the current option details.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I manage multiple tabs, windows, and sessions?

List pages currently open in a browser

Use browser.pages() to inventory open pages across browser contexts:

const pages = await browser.pages();
for (const [index, page] of pages.entries()) {
  console.log(index, page.url());
}

Browser.pages() returns open pages but omits non-visible pages such as background pages by default. Its optional includeAll flag can include them. Use the Browser.pages() API reference for the method signature in your installed version.

Separate browser sessions with contexts

Create a browser context when pages need independent cookies and local storage. Pages opened in a context share that context’s session storage environment, while contexts isolate browser storage from one another. A popup opened by a page remains in the opener’s context.

const contextA = await browser.createBrowserContext();
const contextB = await browser.createBrowserContext();

const pageA = await contextA.newPage();
const pageB = await contextB.newPage();

// Closing a context also closes the pages created in it.
await contextA.close();
await contextB.close();

For details on browser launch, connection, and lifecycle, see Browser management.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Close the browser or disconnect?

Choose cleanup based on who owns the browser process:

  • Call browser.close() to close a browser launched for the task, including its pages.
  • Call browser.disconnect() when Puppeteer is attached to a browser managed by another controller and should only detach. The browser and its pages keep running.

Put cleanup in a finally block so it runs if navigation or page operations fail.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting window and page sizing

  • The viewport changed, but the visible window did not: setViewport() controls the page rendering area, not native window bounds. Use the window-bounds API for window position or state, or resize() for a requested content area.
  • The content area is smaller than the outer dimensions: Browser chrome occupies part of the native window. Measure innerWidth/innerHeight separately from outerWidth/outerHeight.
  • The measured dimensions appear stale after resize: The resize is asynchronous. Wait for a window resize event after initiating the resize before reading the dimensions.
  • The requested content size is constrained: A configured viewport may be limiting the window. Try await page.setViewport(null) before page.resize() when appropriate.
  • Changing device options reloads the page: This can occur when isMobile or hasTouch changes. Set the viewport and emulation options before navigation if possible.
  • A page is missing from browser.pages(): Background pages are excluded by default. Use the optional includeAll behavior when those pages matter.
  • Closing a context also closes tabs: That is expected; closing a browser context closes the pages it owns. Create a separate context for sessions that must remain independent.
  • The browser disappears after cleanup: browser.close() closes the process. Use browser.disconnect() if another controller owns it and it must keep running.

Or skip the browser setup

For a screenshot without writing and maintaining Puppeteer window setup, ScreenshotNeo accepts one GET request with a URL and returns a clean PNG, JPEG, WebP, or PDF. Its API also supports controls such as full-page capture, CSS-selector element capture, viewport and device presets, custom CSS or JavaScript, waiting for a selector or network idle, and PDF settings. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies page verdict and billing status with X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

Frequently Asked Questions

Can Puppeteer control the position of a browser window?

Yes. Use a window-type page to obtain its window ID, then call browser.setWindowBounds() with the desired position or state.

Does browser.pages() return tabs from every browser context?

It returns open pages across contexts, but omits non-visible pages such as background pages by default; the optional includeAll behavior can include those.

Does browser.disconnect() stop the browser?

No. It detaches Puppeteer while leaving the browser and its pages running.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.