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

Await the screenshot call, and separately wait for the page state you need to capture. In Playwright, page.screenshot() is asynchronous: use await so your code does not try to save or use the image before capture finishes. That alone does not mean the page has finished rendering the content you care about. Wait for a meaningful UI condition or URL first, then take the screenshot.

What asynchronous screenshot capture means

A screenshot is the result of browser work: the page must be rendered and the browser must produce image data. In both Playwright and Puppeteer, the screenshot API completes asynchronously. Await its Promise before saving, returning, uploading, or otherwise consuming the image.

There are two separate waits to consider:

  • Page readiness: wait until the page is in the state the image should show, such as a dashboard heading becoming visible or a navigation reaching the expected URL.
  • Capture completion: await the screenshot operation itself before using its result.

A completed screenshot call means the image data is ready; it does not certify that your application loaded the right data or that a particular component appeared. Choose a readiness condition that matches the screenshot’s purpose.

Take an asynchronous screenshot with Playwright

Here is a minimal Node.js example using Playwright. Replace the URL and heading with the page and visible content that matter to your case:

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

(async () => {
  const browser = await chromium.launch();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.getByRole('heading', { name: 'Dashboard' }).waitFor();
    await page.screenshot({ path: 'dashboard.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

The order is intentional: navigate, wait for a visible page condition, then await the screenshot. The path option writes the image to a file; fullPage: true asks for the full page rather than just the current viewport. Without a path, the screenshot call returns image data for your code to handle.

Use a readiness condition that represents the image

The sample waits for a heading. In a real flow, wait for a selector, text, or other user-visible condition that demonstrates the content is ready. For example, a heading may appear before asynchronous dashboard data; if the screenshot must include a populated chart, wait for the chart or its loaded state instead. A generic navigation milestone is useful only when reaching that milestone is sufficient for the image.

Playwright documents navigation conditions including commit, domcontentloaded, and load. These describe navigation progress, not necessarily that application-specific content has rendered. Playwright discourages using networkidle as a testing readiness strategy and recommends web assertions to assess readiness. An application may continue making background requests after the relevant content is already visible, or appear quiet before the element you need has rendered.

Write the image or use its returned data

With { path: 'dashboard.png' }, the awaited call writes the screenshot to that path. If you omit path, retain the returned buffer and pass it to the next operation only after the await completes. For example, you can return the buffer from a helper or send it to another service; the important rule is not to treat an unresolved Promise as image data.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function captureDashboard(page) {
  await page.getByRole('heading', { name: 'Dashboard' }).waitFor();
  return await page.screenshot({ fullPage: true });
}

Callers of captureDashboard should also await it before consuming the result:

const image = await captureDashboard(page);

Wait for navigation caused by an action

If a click or submit causes navigation, coordinate the navigation wait with the action, then verify the destination. Playwright recommends waitForURL() over waitForNavigation(); its documentation calls waitForNavigation inherently racy. Starting the URL wait before the action avoids missing a fast transition:

const urlWait = page.waitForURL('**/reports');
await page.getByRole('link', { name: 'Reports' }).click();
await urlWait;
await page.getByRole('heading', { name: 'Reports' }).waitFor();
await page.screenshot({ path: 'reports.png' });

Adjust the URL pattern and readiness locator to the application. A URL change confirms the navigation target, while the final UI wait confirms the element your screenshot needs. Do not substitute a navigation wait for a page-specific condition when the image depends on data rendered after navigation.

Use Puppeteer when your project already uses it

Puppeteer’s Page.screenshot() also returns a Promise. Await it before writing or processing the image. By default, its result is a Uint8Array; it can return a base64 string when configured to do so.

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();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.locator('h1').wait();
    const image = await page.screenshot({ fullPage: true });
    // Use or write image only after screenshot() resolves.
  } finally {
    await browser.close();
  }
})();

The example uses Puppeteer’s locator wait to make the required heading part of the capture flow. Confirm the precise locator and screenshot options against the Puppeteer version installed in your project; API details can change. The available documentation does not establish that Playwright or Puppeteer is universally faster or better. Prefer the framework your application already uses, and choose based on its browser support and the work you need to do with the output.

Puppeteer documents that creating a new page or closing a page in the same BrowserContext automatically waits for an in-progress screenshot to finish. Do not treat bringToFront() as such a wait: it does not wait for the capture to complete. Explicitly awaiting the screenshot call remains the clearest way to ensure your own code handles the finished image.

For repeatable visual regression checks

A one-off call to page.screenshot() saves an image; it does not tell you whether the page looks correct. For screenshot comparisons in Playwright Test, use await expect(page).toHaveScreenshot(). The assertion waits for two consecutive screenshots to produce the same result and compares the last image with the expectation. It is a Playwright Test feature, not a general replacement for saving screenshots in a script.

Use a regular screenshot when you need an image file or image bytes. Use the test assertion when the goal is to detect a visual difference against an expected image. In either case, establish the intended application state before capture so the comparison is about the page you mean to test.

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

Choosing capture options

Keep the capture configuration focused on what the consumer needs. Playwright’s screenshot API supports saving to a path, full-page capture, clipping, output format, timeout, and cancellation. Check the API reference for the installed version when you need less common options; the code examples here use only the path and full-page options.

  • Viewport or full page: the default is the visible viewport. Set fullPage: true when the image should include content beyond the current viewport.
  • File or in-memory result: provide a path to write the image, or omit it and handle the returned image data after awaiting the call.
  • Specific region: use clipping when only a defined area belongs in the output.
  • Output requirements: select an output format when the downstream process requires a particular image type.
  • Limits and cancellation: set timeout or cancellation behavior only when your workflow needs it, and verify the relevant option semantics in the API version you use.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common problems and fixes

The screenshot is blank or missing page content

Cause: navigation completed, but the application had not rendered the specific content by capture time. Fix: wait for the relevant heading, chart, image, or other page condition before calling screenshot(). Do not assume that waiting for a generic navigation event proves application readiness.

The image is saved before it is complete

Cause: the code starts the screenshot but does not await it before continuing. Fix: use await page.screenshot(...), or return the Promise from an async helper and await that helper at its call site.

The expected file was not created

Cause: the screenshot was requested without a path, or the code assumed the returned image data would be saved automatically. Fix: provide a file path if the API should write the file. Otherwise, retain and explicitly write or pass along the returned image data after awaiting capture.

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.

The script waits for the wrong navigation

Cause: the code relies on a broad or racy navigation wait while an action changes the URL. Fix: create a waitForURL() wait before triggering the action, await it, and then wait for the page-specific element needed in the screenshot.

The page never becomes idle

Cause: the application may keep background network activity running. Fix: use a web assertion for the content the image requires rather than treating networkidle as a general readiness signal.

The capture test is flaky

Cause: the screenshot is being taken before the expected UI is stable, or the task needs a visual comparison rather than a file capture. Fix: wait for an explicit page condition; for visual regression in Playwright Test, use toHaveScreenshot(), which waits for consecutive stable screenshots before comparing.

Or skip the browser setup

If you need an image from a URL rather than a browser automation flow, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. Its clean-shot steps accept cookie and consent banners like a visitor and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers.

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

Here is the cURL call, using the documented endpoint and parameters. Replace the URL with the page to capture and use your API key:

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 documentation for request options. 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 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for ScreenshotNeo’s free plan.

Frequently Asked Questions

Does awaiting a screenshot block the Node.js event loop?

No. Await pauses the surrounding async function until the screenshot Promise resolves; it does not synchronously block the event loop.

Can I take multiple screenshots at once?

The cited API documentation does not establish a general concurrency limit. If you capture multiple pages concurrently, check the limits and resource needs of your browser setup and the API version you use.

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.