Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Choose the wait condition that describes the state your screenshot must show. Use the earliest navigation milestone that is sufficient, then wait for a specific visible element or application condition when content is hydrated or fetched after navigation. There is no universal “page loaded” moment for modern sites: as Playwright’s navigation documentation puts it, “There is no way to tell that there is a ‘loaded’ page, it depends on the page, framework, etc.”
What a browser wait condition actually controls
Navigation and loading are separate phases. A navigation can commit when response headers arrive and the browser updates the document, while parsing, dependent resources and client-side rendering continue afterward. Your automation framework’s wait setting determines how long the navigation call blocks; it does not prove that the visual state you want is complete.
DOMContentLoaded is an early milestone: the HTML has been parsed, but stylesheets, images, iframes and other dependent work may still be in progress. load is later and includes the document’s dependent resources. Neither event guarantees that a single-page application has finished an API request, lazy-loaded an image or rendered a component after JavaScript runs.
Selenium makes the same distinction with the session-wide pageLoadStrategy values normal, eager and none. Its documentation warns that the faster strategies need a sufficient explicit waiting strategy or captures can become flaky.
#1 Best Overall
Which condition should you use?
| Capture requirement | Recommended signal | What it guarantees | What it does not guarantee |
|---|---|---|---|
| Begin as soon as the main response is committed | Playwright commit; Selenium none is the closest coarse option |
The response has started and the document is beginning to load, or WebDriver does not block on a ready state | Parsed HTML, images, styles or application data |
| Capture the parsed document shell | domcontentloaded; Selenium eager |
DOM parsing has reached its milestone | Dependent resources or client-rendered data |
| Include ordinary dependent resources | load; Selenium normal |
Stylesheets, scripts, iframes and images have fired their load milestone | Later lazy data, hydration or post-load UI updates |
| Include a known result, chart or component | Locator visibility, text assertion or another explicit application condition | The target condition is true | Unrelated parts of the page are finished |
| Wait for a brief period without network requests | networkidle |
Playwright observed at least 500 ms with no network connections | That the desired visual state exists; analytics, polling and other activity can make this unsuitable |
These names are framework APIs, not interchangeable standards. Check the version and framework you are using before copying a setting.
A practical decision process
- Define the visual target. Write down what must be visible: the document shell, a fully loaded hero image, a result list, a chart, a consent state or a particular message.
- Pick the earliest lifecycle milestone that satisfies that target. Use
DOMContentLoadedwhen parsed markup is enough. Useloadwhen ordinary dependent resources must be present. Usecommitonly when you will immediately perform an explicit readiness check. - Add a condition for post-load content. If the target is hydrated, fetched or rendered by client code, wait for its locator, text, attribute or application state rather than assuming
loadsettled it. - Set a timeout as a failure boundary. A timeout tells you that the condition was not reached within the allowed period; it is not evidence that an arbitrary sleep produced a ready page. Log which condition timed out so you can diagnose the page.
- Capture only after the assertion passes. Keep the screenshot operation after the readiness check, and use the same viewport, device scale and browser settings for repeatable output.
Playwright: combine navigation with a meaningful assertion
Playwright’s page.goto() defaults to load. You can choose a different waitUntil value, but Playwright often makes an extra waitForLoadState unnecessary because actions auto-wait and an already-reached state resolves immediately. Prefer a web-first assertion tied to the content you need.
Wait for a result list
import { chromium, expect } from '@playwright/test';
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com/search', {
waitUntil: 'domcontentloaded',
timeout: 30_000
});
await expect(page.locator('[data-testid="results"]'))
.toBeVisible({ timeout: 20_000 });
await expect(page.locator('[data-testid="results"] li').first())
.toContainText('Result', { timeout: 20_000 });
await page.screenshot({ path: 'results.png', fullPage: true });
await browser.close();
Here, parsing starts the workflow quickly, while the visible results container and its first item define readiness. Replace the selectors and text with conditions that are stable in your application.
Use load when resources are part of the requirement
await page.goto('https://example.com/report', {
waitUntil: 'load',
timeout: 45_000
});
await expect(page.locator('img[data-chart]')).toBeVisible();
await page.screenshot({ path: 'report.png', fullPage: true });
If an image is lazy-loaded only after scrolling, a load event is insufficient. Scroll or trigger the application behavior, then assert that the image has a usable source or is visible.
Why not make networkidle your default?
Playwright defines networkidle as a 500 ms period with no network connections, but explicitly discourages it as a general readiness signal. A page can be visually ready while a tracker keeps polling, or visually incomplete even after a quiet interval. Use it only when network quietness itself is the requirement and you have verified that the page’s traffic pattern makes it reliable.
When commit is appropriate
commit is useful for workflows that need to start processing as soon as the response is committed. It is not a screenshot-ready state. Follow it with an assertion for the component you intend to capture.
Rank #2
Selenium: map the strategy to an explicit wait
Selenium’s pageLoadStrategy is session-wide. normal waits for the normal page-load completion, eager returns after the DOM is ready, and none does not block on a ready-state milestone. With eager or none, add an explicit wait for the capture target.
Python example with an element condition
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = webdriver.ChromeOptions()
options.page_load_strategy = "eager"
driver = webdriver.Chrome(options=options)
try:
driver.get("https://example.com/search")
results = WebDriverWait(driver, 20).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '[data-testid="results"]'))
)
WebDriverWait(driver, 20).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '[data-testid="results"] li'))
)
driver.save_screenshot("results.png")
finally:
driver.quit()
Use normal instead when the screenshot genuinely requires all ordinary dependent resources and no later application condition is needed. Set none only when you control the subsequent checks carefully.
Choosing between lifecycle events and assertions
Use lifecycle events for document-level requirements
A lifecycle event is appropriate when the thing you are saving is the document structure itself or when the page’s resource loading semantics are known and stable. It is simple and usually faster than waiting for unrelated application activity.
Use assertions for application-level requirements
Assertions are better when a specific list, status, image, modal or chart must appear. They express the condition that matters to the reader of the screenshot and avoid coupling the capture to unrelated requests.
Use both when the page has two phases
For many single-page applications, navigate with domcontentloaded or load, then wait for the target locator. This separates browser navigation from application readiness and makes timeout failures easier to interpret.
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 minuteCommon failure modes and fixes
The screenshot contains a skeleton or empty list
Cause: the capture ran at DOMContentLoaded or load while data was still being fetched.
Rank #3
Fix: wait for a visible result container, a non-empty item, or a status transition that proves the data is rendered.
The run hangs on networkidle
Cause: analytics, polling, advertisements or a long-lived connection prevents a quiet 500 ms interval.
Fix: replace it with a target assertion. If quietness is genuinely required, identify and control the background traffic and retain a finite timeout.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →The screenshot misses images
Cause: images are lazy-loaded after scrolling or after an intersection-observer event.
Fix: scroll the page or the image into view, wait for the image element and its loaded state, then capture. A document load event cannot guarantee content that was not requested yet.
A selector wait times out intermittently
Cause: the selector is unstable, the element is inside an iframe, the page sometimes enters an error state, or the timeout is shorter than the real application path.
Rank #4
Fix: use a stable test identifier, switch to the correct frame, assert an explicit error branch, and collect a trace or diagnostic screenshot at timeout. Increase a timeout only after confirming the condition is correct.
Selenium captures differ between runs
Cause: a session-wide eager or none strategy was selected without a sufficient explicit wait.
Fix: add a WebDriverWait for the actual capture target, and use normal if the workflow cannot define a reliable condition.
Back/forward navigation skips your expected events
Cause: a back/forward cache restoration can bypass ordinary commit, DOMContentLoaded and load events.
Fix: handle history restoration explicitly and assert the visible state after navigation rather than relying only on a lifecycle callback.
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 →Runtime, reliability and cost trade-offs
- Earlier milestones reduce idle time when irrelevant assets are still loading, but increase the chance of capturing incomplete content.
- Broader lifecycle waits improve completeness for resource-heavy documents, but spend time on resources that may not affect the screenshot.
- Specific assertions improve resilience because they track the visual result that matters, although they require a stable selector or state contract.
- Network-idle waits can be expensive and fragile on pages with polling or third-party traffic.
- Timeouts should be bounded and observable. Record the URL, selected condition, elapsed time and failure state so a timeout can distinguish a slow page from a broken selector.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. It accepts the URL in one request and returns PNG, JPEG, WebP or PDF. Its capture options include selector waits, delay or network-idle waits, full-page screenshots with lazy images loaded, custom JavaScript and CSS, device and viewport settings, and more.
Best Value
Use the API with the same target URL you would automate yourself. The full parameter reference is in the ScreenshotNeo documentation.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
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)
Node.js
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 and consent banners, newsletter popups and chat widgets before the shot. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and each response identifies the page verdict and billing result with headers. An MCP server lets AI agents such as Claude, Cursor and other MCP clients take screenshots, inspect page information and capture PDFs. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free.
FAQ
Is load always safer than DOMContentLoaded?
No. It waits for more dependent resources, but it still cannot prove that client-side data or lazy content has rendered. Choose the event that matches the capture and add an assertion when needed.
Does a fixed sleep solve readiness?
It can mask timing problems but cannot express whether the target appeared. A condition-based wait gives a meaningful success or timeout and adapts better to variable response times.
Can I combine a timeout with networkidle?
Yes. A finite timeout is important, but treat expiry as a diagnostic failure rather than proof that the page was ready at the end of the sleep.
What should a readiness condition assert?
Assert the smallest stable fact that proves the screenshot’s purpose: a visible component, non-empty result, loaded image, status text or application state.
Frequently Asked Questions
Which wait condition is best for a page with continuously polling requests?
Use a locator, text or state assertion for the content you need instead of relying on network-idle.
Free tools Windows power users keep installed
One-click scans. No signup required.
Do Playwright actions wait automatically?
Many actions auto-wait for actionable elements; use web-first assertions for the final visual condition and consult the API behavior for your version.
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.

