ScreenshotNeo

BlogHow-to

Use Java Playwright to Take Screenshots at Multiple Viewport Widths

Capture the same page at multiple widths with Playwright Java. Learn how to keep viewport, page state, and image scale consistent for useful comparisons.

By the ScreenshotNeo team4 October 20268 min read

Use Playwright Java’s Page.setViewportSize(width, height) to change the viewport and Page.screenshot(...) to save an image at each width. For pages whose initial layout depends on viewport size, set the viewport before navigating. Keep the height, browser engine, device scale factor, page state, and screenshot scale consistent when comparing widths.

The example below captures viewport screenshots at 375, 768, and 1280 CSS pixels wide. It writes one PNG per width. The code uses Playwright’s Java APIs documented in the screenshots guide and Page API.

Complete Java example

In a Java project with the Playwright dependency configured, save this as ResponsiveScreenshots.java. Pass the page URL as the first command-line argument. The example uses Chromium, a fixed viewport height, and a DOM-ready navigation wait. Replace that readiness choice with an application-specific condition when the page renders important content asynchronously.

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import java.nio.file.Paths;

public class ResponsiveScreenshots {
  public static void main(String[] args) {
    if (args.length != 1) {
      System.err.println("Usage: java ResponsiveScreenshots <url>");
      System.exit(1);
    }

    String url = args[0];
    int[] widths = {375, 768, 1280};
    int height = 900;

    try (Playwright playwright = Playwright.create()) {
      Browser browser = playwright.chromium().launch();
      BrowserContext context = browser.newContext(
          new Browser.NewContextOptions().setViewportSize(widths[0], height));
      Page page = context.newPage();

      for (int width : widths) {
        // Set size before navigation so initial responsive logic sees this viewport.
        page.setViewportSize(width, height);
        page.navigate(url, new Page.NavigateOptions().setWaitUntil(com.microsoft.playwright.options.WaitUntilState.DOMCONTENTLOADED));

        // Add an application-specific readiness wait here if needed, for example:
        // page.locator("main").waitFor();

        page.screenshot(new Page.ScreenshotOptions()
            .setPath(Paths.get("page-" + width + ".png")));
      }

      context.close();
      browser.close();
    }
  }
}

Run it with a URL such as https://example.com. Use a URL you are authorized to access. In a build tool or IDE, configure the Playwright Java dependency and browser installation according to the official Java getting started guide; dependency and browser setup can vary by project and Playwright version.

What this captures

Page.screenshot(...) captures the visible viewport by default. In this example, each output image represents the page as displayed inside a viewport with the selected width and a height of 900 CSS pixels. The screenshots are saved as page-375.png, page-768.png, and page-1280.png.

This is different from a full-page screenshot. A full-page capture extends the image to include the page’s scrollable content; it is useful for documenting the whole document, but it no longer shows how much content fits in a fixed-height viewport. To capture the full page instead, add .setFullPage(true) to the screenshot options:

page.screenshot(new Page.ScreenshotOptions()
    .setPath(Paths.get("full-page-" + width + ".png"))
    .setFullPage(true));

Choose viewport capture when comparing visible layout, folding, navigation, or overflow at different widths. Choose full-page capture when the goal is a long record of the entire document. State which extent your images use so reviewers do not mistake one for the other.

Set the viewport at page or context scope

Resize one page through a sequence

page.setViewportSize(width, height) is direct when one page will be reused for a sequence of widths. Setting it before each navigation makes the initial load happen at the selected size, which matters for sites that choose responsive markup or behavior during startup. The Page API also notes that resizing the viewport resets screen size. If your test needs a distinct window.screen size, configure it separately at context creation.

Set a shared context viewport

A context-level viewport applies to pages created in that context. Use it when several pages should share the same dimensions and emulation settings:

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

The Browser API documents a default viewport of 1280 by 720 when a context uses its default viewport behavior. Set the dimensions explicitly for repeatable captures. For isolated cases where each width should have a fresh page state, create one context per width, configure its viewport in newContext(...), capture, and close that context. This is useful when prior page interactions or application state could affect subsequent captures.

Keep comparisons meaningful

When width is the variable you want to study, hold other capture conditions steady:

  • Use the same browser engine and browser version.
  • Keep viewport height constant unless height is also under study.
  • Keep device scale factor and screenshot scale fixed.
  • Wait for the same meaningful application state at every width.
  • Use the same URL, authentication state, cookies, locale, and content data.
  • Decide whether animations, video, and live content should be frozen or allowed to change.
  • Use viewport screenshots for fixed-viewport layout comparisons; use full-page screenshots only when comparing full documents.

Navigation completing does not necessarily mean that client-side rendering, images, fonts, or other asynchronous work has settled. Choose an application-specific wait, such as waiting for a known element or a state your application exposes. A fixed delay can be useful for a known animation or delayed widget, but it can also waste time or still be too short when network and rendering times vary.

Viewport width is not full device emulation

Changing only the viewport width tests responsive layout at that viewport. It does not necessarily reproduce a physical phone or tablet. A device-style test can also involve screen dimensions, device scale factor, touch support, mobile behavior, and user agent. Playwright’s emulation guide and Browser API document these context controls.

For a straightforward desktop responsive check, changing only the viewport is often the clearest experiment. For mobile behavior, configure the relevant device properties and say which ones you used. A device scale factor affects the relationship between CSS pixels and image pixels; it can change output dimensions and image detail.

Screenshot options to choose deliberately

The screenshot API includes options for format, output scale, quality, masking, animation handling, and injected styles. Select them to match the purpose of the capture rather than changing them between widths:

Choice When it helps Consideration
Viewport or full page Visible layout comparison or whole-document record These answer different questions; full page can produce very tall images.
CSS or device scale CSS scale gives one image pixel per CSS pixel; device scale captures at device pixel density. Use the same scale and device scale factor across captures.
PNG, JPEG, or another documented format Choose based on whether you need lossless detail or smaller photographic output. For JPEG, quality affects file size and visible artifacts. Check the API’s supported formats for your installed version.
Animation handling Reduce variation from animated elements in repeat captures. Choose a behavior that fits whether animation itself is under review.
Masking or injected style Hide dynamic regions or apply capture-only styling for comparison. Document the changes because they alter what the screenshot represents.

For exact option names and behavior, consult the Java Page API. Element screenshots are also available when the comparison should focus on one component rather than the whole viewport; see the Locator API.

Or skip the browser setup

ScreenshotNeo provides a screenshot API and MCP server. A single GET request can return an image or PDF. For example, this cURL request captures a page as WebP:

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

See the ScreenshotNeo API documentation for the request options. Python and Node.js versions are available too:

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}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Learn more at ScreenshotNeo, or sign up for 1,000 free screenshots a month with no card.

Troubleshooting

Symptom Likely cause What to do
All files look the same despite different widths The viewport may be changed after navigation, or the page may use a fixed-width layout. Set the width before each navigation, confirm the viewport-dependent CSS actually changes, and inspect the page’s responsive breakpoints.
Screenshot misses content that appears later Navigation finished before asynchronous rendering or loading completed. Wait for a meaningful selector or application-ready condition before capturing.
Images or fonts are missing Resources may still be loading, blocked, or failing. Wait for the relevant resources or page state; inspect the browser console and network behavior for failed requests.
Image dimensions do not equal the requested CSS dimensions Device scale factor or screenshot scale changes output pixel dimensions. Set a consistent context device scale factor and use the same screenshot scale at every width.
Mobile screenshot does not match a real device Only the viewport was changed. Configure the additional emulation properties relevant to the target device, such as touch, mobile behavior, screen dimensions, user agent, and device scale factor.
Repeated captures differ unexpectedly Dynamic data, animation, ads, timestamps, or persisted page state changed. Use stable test data, consistent state, and appropriate masking or animation options. Use a fresh context per width if state carries over.
Capture fails or output path is missing The destination directory may not exist or may not be writable, or the browser/context may already be closed. Create the directory first, use a writable path, and close the context only after all screenshots finish.

Performance, reliability, and storage

Each loop iteration navigates and waits, so page load time is usually the largest cost in elapsed time. Reusing one page reduces setup overhead, while a fresh context per width provides more isolation at the cost of extra context creation. Capture widths sequentially when repeatability and a stable browser workload matter; parallel pages can shorten elapsed time for independent captures, but consume more browser resources and may change server load or timing.

PNG files preserve detail but can be large, especially for full-page images and high device scale factors. Use a documented lossy format and suitable quality when smaller files matter more than pixel-perfect detail. Keep width in each filename or associated metadata so an image remains interpretable later. For durable visual comparisons, also record browser engine/version, viewport height, device scale factor, screenshot scale, URL, and the readiness condition.

Close each context after use and then close the browser. This releases browser resources and avoids leaving pages alive across repeated runs. The example uses explicit context and browser closure; a try-with-resources block closes Playwright itself.

FAQ

Can I capture more than three widths?

Yes. Add the desired integer CSS pixel widths to the array. Use clear filenames and keep the other capture settings consistent.

Does changing viewport width change the browser’s screen size?

Page.setViewportSize() changes the viewport and resets screen size. If screen dimensions matter independently, set the context screen size as well, as documented by the Browser API.

Can I capture just a responsive component?

Yes. Use a locator’s screenshot method for a specific element. This is useful when surrounding page content would distract from the component comparison.

Should I use one page or one context per width?

Reuse a page for a simple sequential sweep. Use separate contexts when each width needs isolated storage, cookies, or application state.