ScreenshotNeo

BlogHow-to

How to Get the Window Size in Playwright

Read Playwright’s configured viewport with `page.viewportSize()` or inspect the live CSS viewport with `window.innerWidth` and `window.innerHeight`.

By the ScreenshotNeo team1 October 20266 min read

In Playwright, “window size” usually means the page’s emulated viewport. In JavaScript or TypeScript, read the configured viewport with page.viewportSize(); read the live CSS viewport from the page with window.innerWidth and window.innerHeight.

const configured = page.viewportSize();
console.log(configured?.width, configured?.height);

const live = await page.evaluate(() => ({
  width: window.innerWidth,
  height: window.innerHeight,
}));
console.log(live);

The configured size describes Playwright’s viewport emulation. The browser-side values describe the running page’s current CSS viewport. Neither is a measurement of the native operating-system window including title bar and borders.

1. Choose which size you need

Need Use What it tells you
What size Playwright configured page.viewportSize() / page.viewport_size The fixed viewport configured for the page, or null when there is no fixed viewport.
What CSS layout sees right now window.innerWidth and window.innerHeight in page.evaluate() The live page viewport in CSS pixels after scripts and resizing have run.
Native browser window including chrome No portable Playwright viewport API Playwright’s documented cross-browser abstraction is the page viewport, not OS window decorations.

For responsive layout assertions, use the live CSS values or test at a known configured viewport. A page’s total document height is different: use document.documentElement.scrollHeight when you need the full content height.

2. Read dimensions in JavaScript or TypeScript

In a Playwright Test test, page is provided by the test fixture:

import { test, expect } from '@playwright/test';

test('reports viewport dimensions', async ({ page }) => {
  const configured = page.viewportSize();
  console.log('configured:', configured);

  const live = await page.evaluate(() => ({
    width: window.innerWidth,
    height: window.innerHeight,
  }));
  console.log('live CSS viewport:', live);

  expect(live.width).toBe(1280);
  expect(live.height).toBe(720);
});

The configured value is often the right choice when you want to confirm test setup. The evaluated value is useful when asserting behavior from the page’s point of view or after a resize.

3. Set a deterministic viewport

Playwright Test documents a default viewport of 1280 × 720. Set it explicitly when the test depends on a particular responsive breakpoint, so the intended dimensions are clear in the test configuration.

Configure a Playwright Test project

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    viewport: { width: 1280, height: 720 },
  },
});

Override the viewport for a test

import { test } from '@playwright/test';

test.use({ viewport: { width: 1600, height: 1200 } });

test('wide layout', async ({ page }) => {
  const size = page.viewportSize();
  console.log(size);
});

Create a browser context with a fixed viewport

const context = await browser.newContext({
  viewport: { width: 1280, height: 1024 },
});
const page = await context.newPage();
await page.goto('https://example.com');

Context-level settings are useful when creating pages outside the Playwright Test fixture or when several pages should share the same emulation.

Resize one page

await page.setViewportSize({ width: 1600, height: 1200 });
const live = await page.evaluate(() => ({
  width: window.innerWidth,
  height: window.innerHeight,
}));

Set the size before navigation when possible. Playwright’s Page API notes that many sites do not expect phones to change size, so setting the viewport before navigating avoids testing a layout that was initialized at a different size. Resizing can also reset screen; when coordinating screen and viewport emulation, configure both on the context.

4. Python, Java, and C# equivalents

Python

context = await browser.new_context(
    viewport={"width": 1280, "height": 1024}
)
page = await context.new_page()

configured = page.viewport_size
live = await page.evaluate(
    "({width: window.innerWidth, height: window.innerHeight})"
)
print("configured:", configured)
print("live CSS viewport:", live)

await page.set_viewport_size({"width": 1600, "height": 1200})

Python uses the viewport_size property and set_viewport_size(). Viewport width and height are in pixels. The Python option no_viewport disables the fixed viewport.

Java

BrowserContext context = browser.newContext(
    new Browser.NewContextOptions().setViewportSize(1280, 1024));
Page page = context.newPage();

Page.ViewportSize configured = page.viewportSize();
System.out.println(configured.width + " x " + configured.height);

Object live = page.evaluate(
    "() => ({width: window.innerWidth, height: window.innerHeight})");
System.out.println(live);

page.setViewportSize(1600, 1200);

C#

await using var context = await browser.NewContextAsync(new()
{
    ViewportSize = new ViewportSize { Width = 1280, Height = 1024 }
});
var page = await context.NewPageAsync();

var configured = page.ViewportSize;
var live = await page.EvaluateAsync<object>(
    "() => ({ width: window.innerWidth, height: window.innerHeight })");
Console.WriteLine($"configured: {configured?.Width} x {configured?.Height}");
Console.WriteLine(live);

await page.SetViewportSizeAsync(1600, 1200);

5. Understand viewport and host-window options

A fixed viewport makes layout tests repeatable across runs. Playwright documents that viewport: null makes the viewport depend on the host operating-system window and makes execution nondeterministic. Python documents the corresponding no_viewport option for disabling a fixed viewport.

  • Use explicit width and height for deterministic responsive tests and screenshots.
  • Use null or no_viewport only when host-window-dependent sizing is intentional.
  • Do not treat page.viewportSize() as the physical outer browser size.
  • Use window.innerWidth and window.innerHeight when the page’s current CSS dimensions are what matter.

Playwright’s viewport dimensions are expressed in pixels for the emulated page. The CSS values are the useful ones for checking media queries and layout behavior.

6. Troubleshooting

Symptom Likely cause Fix
page.viewportSize() returns null The page has no fixed viewport, such as when viewport emulation is disabled. Set viewport: { width, height } in the test or context if you need deterministic dimensions; otherwise inspect the live values in the page.
The configured size and window.innerWidth differ You are comparing the configured emulation with the live page state, or the page was resized. Read both values after the page is ready and check for calls to setViewportSize(). Use the value that matches the question being tested.
Responsive layout assertions vary between runs The viewport may depend on the host window or be set inconsistently. Configure a fixed viewport before navigation and use the same dimensions in the test project.
Layout looks wrong after resizing The site may have initialized while at the earlier dimensions; resizing can also reset screen. Prefer setting the viewport before navigation. Configure context-level screen and viewport together when both matter.
The number is not the visible browser window size Viewport APIs describe the page area, not native browser borders or title bars. Use viewport dimensions for cross-browser page layout tests; native chrome dimensions are outside this documented abstraction.

7. Performance, reliability, and cost

Reading the configured viewport is a local API property access. Reading live dimensions evaluates a short expression in the page. For reliable layout checks, configure the viewport once before navigation instead of repeatedly resizing between assertions. A fixed viewport also avoids host-machine window dimensions changing test results.

If the goal is to obtain a rendered image rather than build a browser automation flow, ScreenshotNeo is a website screenshot API and MCP server: a single request returns an image or PDF. Its pricing is free for 1,000 shots per month, then $5 for 3,000 shots on Starter; yearly billing gives two months free. Every feature is on every plan.

8. Or skip the browser setup

ScreenshotNeo captures a URL without requiring you to configure a Playwright browser locally. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, with no card required.

9. FAQ

What is Playwright’s default viewport?

Playwright Test documents a default viewport of 1280 × 720.

Should I use page.viewportSize() or window.innerWidth?

Use the former for configured emulation and the latter for the live CSS viewport seen by the page.

Can Playwright return the browser’s outer window dimensions?

Playwright’s documented cross-browser size controls concern the page viewport, not native browser chrome such as borders and title bars.

When should I set the viewport?

Before navigation when possible, especially when the test exercises responsive behavior.

References