ScreenshotNeo

BlogHow-to

Fix Playwright Screenshot Timeout When Capturing a Web Page

Diagnose whether navigation, screenshot capture, or the test itself is timing out, then apply the right Playwright setting and readiness check.

By the ScreenshotNeo team4 October 20267 min read

To fix a Playwright screenshot timeout, first identify which operation timed out: navigation, page.screenshot(), or the overall test. Give the screenshot its own finite timeout when capture is the failing operation, and wait for a page-specific readiness condition before taking it. Increasing a navigation timeout will not change the screenshot timeout.

The Page API documents page.screenshot() with a default timeout of 0 (no timeout). A value such as 30 seconds below is an illustrative limit, not a Playwright recommendation or a guarantee that the page is ready. See the Playwright Page API and Playwright Test timeout guide.

1. Identify which timeout is firing

Read the operation named in the error and, if available, inspect the trace around the failure. The timeout scope matters:

Failing operation What to inspect Typical adjustment
page.goto() or a navigation wait Navigation milestone and navigation timeout Choose a suitable waitUntil and configure navigation timing if needed
page.screenshot() The screenshot call and its timeout option Set timeout on the screenshot call or a relevant shared default
Test or worker reports the test exceeded its limit Playwright Test’s test timeout Review the test-level timeout configuration

These are separate limits. A larger test timeout does not necessarily change a per-call screenshot limit, and changing the screenshot timeout does not make navigation or application rendering complete sooner.

2. Set a timeout on the screenshot operation

Use the per-call option when the screenshot operation itself is the one that fails:

await page.screenshot({ path: 'page.png', timeout: 30_000 });

Choose a value appropriate to your runner and page. The API documents that the screenshot timeout defaults to 0, meaning no timeout. It also documents shared defaults through actionTimeout, page.setDefaultTimeout(), and browserContext.setDefaultTimeout(). These broader settings can affect other timeout-accepting methods, so prefer a per-call value when only one capture needs a different limit.

3. Separate navigation from application readiness

Navigation milestones describe different stages:

waitUntil What it waits for When it can help
commit The response is received and document loading begins When you want to proceed after the response starts
domcontentloaded The DOM content-loaded event When initial document parsing is enough to begin a page-specific readiness wait
load The load event When the page’s load event is the milestone you require
networkidle No network connections for at least 500 ms Use only when that exact condition fits; Playwright discourages it as a general test readiness strategy

For a client-rendered page, navigation completing may not mean the content you want is visible. Wait for a stable locator or another observable application state that corresponds to the desired screenshot. Replace the example locator below with one specific to the page:

const url = 'https://example.com';

await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.getByRole('main').waitFor({ state: 'visible' }); // Replace with the page-specific ready condition.
await page.screenshot({ path: 'page.png', timeout: 30_000 });

Playwright generally auto-waits before actions. Its Page API says waitForTimeout() should only be used for debugging because timer-based waits can make tests flaky. A fixed delay is not a reliable substitute for checking that the needed content is ready.

4. Use a complete Node.js capture pattern

This runnable example accepts a URL from the command line, waits for the DOM content-loaded milestone and a visible main landmark, then takes a bounded screenshot. The landmark is only an example: choose a locator that exists when the page content you need is ready.

const url = process.argv[2];
if (!url) throw new Error('Usage: node capture.mjs https://example.com');

const { chromium } = await import('playwright');
const browser = await chromium.launch();

try {
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
  await page.getByRole('main').waitFor({ state: 'visible', timeout: 15_000 });
  await page.screenshot({ path: 'page.png', timeout: 30_000 });
} finally {
  await browser.close();
}

Save this as capture.mjs in a project with Playwright installed, then run node capture.mjs https://example.com. The navigation, readiness wait, and screenshot each have an explicit limit in this example; tune them independently for your page and environment.

5. Check capture size and work

Reduce capture work only when it still meets the screenshot requirement:

  • fullPage defaults to false. Set it to true only when the full scrollable page is needed; a full-page image may involve more content than a viewport capture.
  • The screenshot scale option can use 'css', which produces one output pixel per CSS pixel and keeps high-DPI screenshots smaller. This may reduce output size, but the documentation does not describe it as a universal timeout fix.
  • Capture only the required page state and avoid waiting for unrelated application activity when a meaningful ready condition is available.
await page.screenshot({
  path: 'viewport.png',
  fullPage: false,
  scale: 'css',
  timeout: 30_000
});

6. Troubleshoot common Playwright screenshot hangs

Symptom Likely cause What to do
Error names page.goto() Navigation did not reach the selected milestone before its limit Inspect the URL and navigation error, choose an appropriate waitUntil, and set navigation timing deliberately. Do not expect the screenshot timeout to fix navigation.
Error names page.screenshot() The capture operation exceeded its configured timeout Set or inspect the screenshot’s timeout. If using a shared default, check whether it applies to other methods too.
The test runner ends the test The overall Playwright Test time limit was reached Review the test timeout separately from action and navigation settings.
Screenshot completes but the page looks incomplete Navigation finished before the client-rendered content reached its desired state Wait for a page-specific visible element, text, or state before capture.
Wait for networkidle never finishes The page continues making network connections, or the condition does not match its behavior Use a meaningful application readiness condition instead. networkidle requires 500 ms without network connections and is discouraged as a general test wait.
A fixed sleep passes sometimes and fails other times Elapsed time does not establish that the required page state exists Replace it with a locator or observable condition; reserve waitForTimeout() for debugging.
Only a very large page capture is slow The capture includes more page area or image pixels than needed Use viewport capture if full-page output is unnecessary, and consider scale: 'css' for smaller high-DPI output. Neither setting guarantees a fix.

Do not assume a longer timeout will repair a browser that is stuck, a failed network request, or a page that never reaches the chosen state. Use the failure location and trace to find which operation is waiting.

7. Reliability, performance, and cost considerations

A finite per-call screenshot timeout makes the capture’s limit explicit. A larger timeout can give slow captures more time, but it also lets a stuck operation occupy the test longer. Keep navigation, readiness, screenshot, and overall test limits conceptually separate so a failure identifies the stage that needs attention.

For performance, capture only the area and resolution the consumer needs. Full-page capture and high-DPI output can increase the image’s size; CSS-pixel scale can keep high-DPI screenshots smaller. The cited Playwright documentation does not give a universal timeout recommendation or a performance benchmark, so measure behavior in your own environment.

Playwright timeout configuration has no per-screenshot service price in the cited documentation. For a hosted capture alternative, ScreenshotNeo’s published plans are free for 1,000 shots per month with no card, then $5 for 3,000, $15 for 15,000, $39 for 60,000, $99 for 250,000, or $249 for 1,000,000; yearly billing gives two months free. Every feature is on every plan. See ScreenshotNeo for the product details.

Or skip the browser setup

ScreenshotNeo takes a screenshot with one GET request. See the API documentation for setup and options.

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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
  • 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 are never billed. Responses identify the page verdict and billing status in headers.
  • An MCP server lets AI agents, including Claude, Cursor, and other MCP clients, take screenshots.
  • 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000.

Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.

Frequently asked questions

How do I increase the Playwright screenshot timeout?

Pass a larger finite value in milliseconds as timeout to page.screenshot(), for example 30_000. First confirm the error names screenshot capture; navigation and test-run limits are separate.

Does page.screenshot() time out by default?

The Page API documents its screenshot timeout default as 0, which means no timeout. A shared timeout configuration may also affect timeout-accepting methods.

Should I wait for networkidle before every screenshot?

No. It represents 500 ms without network connections, and Playwright discourages it as a generic test readiness wait. Wait for the page-specific state that means the content you need is ready.

Will fullPage: true fix a screenshot timeout?

No general fix is documented. It captures the full scrollable page; use it only when that output is required. Otherwise the default viewport capture may do less work.