Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
With Playwright for Python, set the screenshot’s own timeout in milliseconds: page.screenshot(path="site.png", full_page=True, timeout=15_000). Give navigation its own budget too: a timeout on page.goto() limits page loading, while the screenshot timeout limits the capture operation. Playwright’s documented default for both page and locator screenshots is 30,000 milliseconds; passing 0 disables that operation’s timeout.
Set separate budgets for navigation and capture
A page can finish navigating but still take time to become ready for a screenshot. Conversely, navigation can fail before the screenshot call is reached. Use a separate timeout for each operation so you can tell which stage exceeded its budget and adjust it without making every wait longer.
Runnable synchronous Playwright example
This example gives navigation up to 60 seconds and screenshot capture up to 15 seconds. Change the URL and budgets to suit the page and the deadline for your job.
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError, sync_playwright
URL = "https://example.com"
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
try:
# Navigation and screenshot capture have separate budgets.
page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
page.screenshot(
path="example.png",
full_page=True,
timeout=15_000,
)
except PlaywrightTimeoutError:
print("Navigation or screenshot exceeded its timeout")
finally:
browser.close()
Playwright’s Python API expresses these values in milliseconds, so 15_000 means 15 seconds. The screenshot API documents a default of 30,000 milliseconds, or 30 seconds. The timeout value is an upper bound, not a request to wait that long: the call can return sooner when it completes.
#1 Best Overall
Identify which operation timed out
The sample catches both operations in one block for brevity. If your recovery action depends on the failing stage, catch the exception around each call separately:
try:
page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
except PlaywrightTimeoutError:
print("Navigation timed out")
else:
try:
page.screenshot(path="example.png", full_page=True, timeout=15_000)
except PlaywrightTimeoutError:
print("Screenshot capture timed out")
Playwright’s Python timeout exception is imported as TimeoutError from playwright.sync_api. Catch it around the operation you want to handle; keep browser cleanup in a finally block so a timeout does not leave the browser open.
What each Playwright timeout controls
Playwright has per-call timeouts and defaults for classes of calls. A per-call value is clearest when one operation needs a different budget from the rest.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →| Setting | What it limits | When it is useful |
|---|---|---|
page.goto(..., timeout=...) |
The navigation operation. | Give page loading a budget that reflects the site’s response time and your job deadline. |
page.screenshot(..., timeout=...) |
The screenshot operation, including work Playwright must complete for that capture. | Limit how long the capture itself can hold up the job. |
page.set_default_timeout(...) |
The default maximum time for timeout-aware methods when no per-call value is supplied. | Set a page-level default, then override individual calls that need a different limit. |
page.set_default_navigation_timeout(...) |
The default navigation timeout. | Set navigation’s default independently. Playwright documents that this setting takes priority over page.set_default_timeout() for navigation. |
For example, set defaults once after creating the page, then use a shorter timeout for a particular capture:
page.set_default_timeout(20_000)
page.set_default_navigation_timeout(60_000)
page.goto(URL, wait_until="domcontentloaded")
page.screenshot(path="example.png", full_page=True, timeout=15_000)
Here, navigation uses its 60-second default; other timeout-aware calls without an explicit value use the 20-second page default; and the screenshot has its own 15-second limit. An explicit per-call timeout lets the code show the budget where that operation occurs.
Rank #2
Using zero
Passing timeout=0 disables the timeout for that Playwright operation. That means it can wait indefinitely if it never completes. Use zero only when an external watchdog or job-level deadline will stop the overall task; otherwise, a stuck page can tie up a worker without a clear recovery point.
Choose readiness conditions before increasing the timeout
A timeout is not a readiness condition. It sets a limit on how long an operation may take; it does not determine whether a page is useful to capture. The example uses wait_until="domcontentloaded" for navigation, then lets the screenshot operation run. That is a reasonable starting pattern when you do not need every background request to finish before capture.
If the content you need appears after navigation, wait for a meaningful page condition before taking the screenshot rather than adding an arbitrary sleep. For instance, wait for the selector that represents the report, chart, or other target content in your own page, then take the screenshot with a separate capture timeout. Playwright’s documentation discourages fixed timeout waits in production tests because they can be flaky: a fixed delay may be unnecessarily long on a fast run and still too short on a slow one.
Decide what “ready” means for the capture. A page’s document loading, a particular element appearing, and late-loaded images are different conditions. The screenshot timeout limits the screenshot call; it does not replace a deliberate readiness check before that call.
Full-page and element screenshot timeouts
Full-page capture
Pass full_page=True to capture the full scrollable page rather than only the current viewport:
page.screenshot(
path="full-page.png",
full_page=True,
timeout=15_000,
)
If this times out but a normal viewport capture succeeds, that is a useful diagnostic: the problem may be associated with the full-page capture or content that appears farther down the page. Try a viewport screenshot to narrow down the failing operation before raising the limit.
Free tools Windows power users keep installed
One-click scans. No signup required.
Capture one element
Use a locator’s screenshot method to save a specific element. It accepts a timeout too:
page.locator(".header").screenshot(
path="header.png",
timeout=10_000,
)
Unlike a page screenshot, a locator screenshot waits for actionability checks and scrolls the element into view before capturing it. Its documented default is also 30,000 milliseconds, and 0 disables its timeout. If this call times out, check that the selector matches the intended element and that the element becomes actionable; a slow capture is not the only possible cause.
Set a useful timeout without hiding failures
There is no single timeout that fits every page or capture job. Choose budgets based on the task’s overall deadline and the stage that needs time, then make a timeout produce a visible outcome: log which operation failed, save diagnostic context if your workflow supports it, or retry under a bounded policy. Raising every timeout can make a stuck job take longer to detect without making the page more reliable.
- Use a navigation budget appropriate to the sites being loaded.
- Set screenshot capture separately, especially when full-page captures or large pages are involved.
- Wait for a relevant element or assertion when the screenshot depends on specific content.
- Keep an outer job deadline if you disable a Playwright operation timeout.
- Close the browser in cleanup code, including when a timeout occurs.
Playwright’s page API documents set_default_timeout() as the default maximum for methods that accept a timeout. It also documents that set_default_navigation_timeout() takes priority for navigation operations. Prefer explicit per-call values for exceptions to those defaults, so a later reader can see which stage is intentionally allowed more time.
Recommended Free Tools
How Selenium differs
Selenium’s Python WebDriver API provides driver.save_screenshot(path) for saving the current browser view. The cited API documents page-load and script timeout controls, but does not show a Playwright-style timeout= keyword on save_screenshot. That means you should not copy Playwright’s per-call screenshot syntax into Selenium code.
| Question | Playwright Python | Selenium Python |
|---|---|---|
| Per-call screenshot timeout? | page.screenshot(..., timeout=...) accepts one. |
The cited save_screenshot(path) API does not show a per-call timeout keyword. |
| Navigation budget? | Set timeout on page.goto() or configure the navigation default. |
Use the WebDriver page-load timeout control. |
| Full-page and element helpers? | The documented screenshot API includes full-page capture; locator screenshots capture an element. | The cited method is save_screenshot(path) for the current browser view. |
| Timeout handling? | Catch Playwright’s Python TimeoutError around the operation. |
The cited API describes separate WebDriver timeout controls; enforce a whole-operation deadline at the job or test-runner layer if needed. |
If your project already uses Selenium, configure the relevant page-load or script budgets and put an outer deadline around the job when you need to constrain the total work. Choose the timeout control for the operation that is actually hanging rather than assuming the screenshot method exposes the same control as Playwright.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common timeout problems and fixes
page.goto() fails before a screenshot is saved
The navigation budget expired, so execution did not reach the screenshot call. Catch navigation timeouts separately, then decide whether the site needs a larger navigation budget or a different navigation readiness condition. Do not increase the screenshot timeout to address a failure that happens during goto().
The viewport works but a full-page capture does not
Try a viewport capture to determine whether the full-page operation or content outside the initial viewport is involved. If the full-page result is needed, inspect how the lower page content becomes available and choose an appropriate readiness condition before changing the capture budget.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesAn element screenshot never reaches the capture
Locator screenshots perform actionability checks and scroll the element into view. Verify the selector against the loaded page and make sure the element can become actionable. If the desired element appears asynchronously, wait for that element before capturing it.
Best Value
The script appears to wait forever
Check whether a timeout was explicitly set to 0 or whether the relevant operation has a default you did not intend. Restore a finite per-call or default budget, or ensure an external watchdog will terminate the job. A timeout set on navigation does not automatically express the separate capture budget; set both where needed.
The browser remains open after a failure
Put browser shutdown in a finally block, as in the runnable example. This makes cleanup run after a successful capture and after a caught Playwright timeout.
Or skip the browser setup
If you need a screenshot from Python but do not want to manage a browser session, ScreenshotNeo provides a website screenshot API. A single GET request returns an image or PDF; the following Python call follows its API pattern and saves the response body:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteimport requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
See the ScreenshotNeo API documentation for the request options. The client call includes a 90-second request timeout; the example does not set a separate browser-navigation timeout in your Python process.
ScreenshotNeo accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status in headers. Its MCP server offers take_screenshot, get_page_info, and capture_pdf 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. Every feature is on every plan.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
Quick Recap
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.

