Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk8 min

How to Wait for a Page to Load in Selenium Before a Screenshot

Selenium’s navigation wait ends at document readiness, not necessarily when a dynamic app is visually ready. Learn which explicit condition to wait for before capturing a reliable screenshot.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the state your screenshot actually needs, then capture it. Selenium’s default navigation behavior waits for the document’s readyState to reach complete, but JavaScript applications can continue fetching data, rendering components, loading images, or changing the page afterward. For dependable screenshots, use an explicit wait for a page-specific condition—such as a result panel becoming visible or a loading indicator disappearing—before calling save_screenshot().

The reliable Selenium sequence

A screenshot is a snapshot of the browser at one instant. The correct sequence is:

  1. Open the URL or perform the interaction that changes the page.
  2. Wait for an observable condition that represents the state you need.
  3. Capture the current window.

Here is a practical Python pattern:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

url = "https://example.com"
driver = webdriver.Chrome()
try:
    driver.get(url)

    # Replace this with a stable marker on your page.
    WebDriverWait(driver, 15).until(
        EC.visibility_of_element_located(
            (By.CSS_SELECTOR, "main .page-ready-marker")
        )
    )

    driver.save_screenshot("page.png")
finally:
    driver.quit()

The selector and 15-second timeout are illustrative. Choose a locator that identifies the content required in the image, not a generic element that appears on every route.

Why driver.get() is not enough

With the default page-load strategy, Selenium waits for the browser’s document readiness state to reach complete and for resources covered by the browser’s page-load behavior. That is useful for traditional pages, but it is not a promise that a single-page application has finished its work. A JavaScript app may reach complete while it is still requesting API data, mounting a component, applying a route transition, or replacing a loading skeleton.

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

After a click, form submission, or client-side route change, the same issue is even more common: the browser may not perform a new top-level navigation at all. Your code must wait for the post-interaction state explicitly.

Choose a condition that matches the screenshot

Wait for a target element to become visible

Use visibility_of_element_located when the screenshot must contain a panel, heading, chart, or other element that is rendered and visible:

WebDriverWait(driver, 20).until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "#report"))
)

Visibility generally means the element is present and has a rendered size. It does not prove that every descendant image or canvas has finished drawing, so add a more specific condition when those assets matter.

Wait for a loading indicator to disappear

For an application with a stable spinner or skeleton, wait for it to become invisible or be removed:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
WebDriverWait(driver, 20).until(
    EC.invisibility_of_element_located((By.CSS_SELECTOR, ".loading-spinner"))
)

This is strongest when the application displays the indicator during every relevant load and removes it only after the content is usable.

Wait for a page-specific state marker

A dedicated marker is often the most maintainable approach. For example, your application could add data-render-state="ready" to a root element:

WebDriverWait(driver, 20).until(
    EC.presence_of_element_located(
        (By.CSS_SELECTOR, '[data-render-state="ready"]')
    )
)

Prefer a semantic marker over a styling class that designers may rename.

Wait for text, a title, or a URL change

Selenium includes conditions for a title containing text, a URL changing, and an element containing text. These are useful after navigation or a filter action:

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.
WebDriverWait(driver, 15).until(
    EC.text_to_be_present_in_element(
        (By.CSS_SELECTOR, "#status"), "Complete"
    )
)
WebDriverWait(driver, 15).until(EC.title_contains("Dashboard"))

Use a condition tied to the intended state. A URL change alone may happen before the page’s data is painted.

Wait until a particular image has decoded

An image element can be visible before its pixels are available. Poll the browser for a completed load and nonzero dimensions:

from selenium.webdriver.support.ui import WebDriverWait

image = (By.CSS_SELECTOR, "img.hero")
WebDriverWait(driver, 20).until(
    lambda d: d.execute_script(
        """
        const img = document.querySelector(arguments[0]);
        return img && img.complete && img.naturalWidth > 0 && img.naturalHeight > 0;
        """,
        "img.hero"
    )
)

This is a page-specific implementation check, not a guarantee supplied by Selenium’s general page-load wait. Handle pages where the image is legitimately optional or can fail by defining the intended fallback.

Explicit waits, implicit waits, and sleeps

Approach How it behaves Best use Main risk
Explicit wait Polls one condition until it succeeds or the timeout expires. A screenshot that depends on a known element or state. A poor locator can wait for the wrong thing.
Implicit wait Applies a global lookup delay to element searches. Projects that intentionally want one global lookup policy. Combining it with explicit waits can make total timing unpredictable.
Fixed sleep Pauses for exactly the requested duration. Last-resort timing workarounds when no observable signal exists. Too short is flaky; too long wastes every run.

For screenshot synchronization, explicit waits usually communicate intent best. Avoid casually mixing implicit and explicit waits. If the site exposes no reliable readiness signal, a short delay may be unavoidable, but treat it as a compromise rather than proof that rendering is complete.

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

Document readiness and page-load strategies

Selenium sessions support three page-load strategies:

Strategy Navigation returns at Screenshot implication
normal complete, with the resources covered by normal page-load behavior. Most conservative navigation setting, but dynamic application work can continue afterward.
eager interactive. Returns sooner; images and other resources may still be loading, so an explicit wait is essential.
none Does not block WebDriver on document readiness. Useful only when your own synchronization is comprehensive.

Configure the strategy when creating the driver:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.page_load_strategy = "eager"
driver = webdriver.Chrome(options=options)

Changing the strategy affects navigation for the session; it does not replace waits for application data, animations, images, or post-click updates. document.readyState == "complete" is a valid condition when that exact browser state is your requirement, but it is not a universal “visually settled” test.

Set an upper bound without confusing it with readiness

The page-load timeout limits how long Selenium will block while navigation completes. It is separate from the application-specific condition used before capture:

driver.set_page_load_timeout(45)
driver.get("https://example.com")
WebDriverWait(driver, 20).until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "main"))
)

A navigation timeout tells you that the browser did not complete navigation within the configured limit. An explicit-wait timeout tells you that the condition you selected never became true in its own limit. Keep both values intentional so failures identify the correct phase.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Waiting after clicks, forms, and client-side routes

Do not assume a click has finished because the click command returned. Wait for the old state to disappear or the new state to appear:

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

old_panel = (By.CSS_SELECTOR, ".results.loading")
new_panel = (By.CSS_SELECTOR, ".results.ready")

driver.find_element(By.CSS_SELECTOR, "button.run-report").click()
WebDriverWait(driver, 15).until(EC.invisibility_of_element_located(old_panel))
WebDriverWait(driver, 15).until(EC.visibility_of_element_located(new_panel))
driver.save_screenshot("report.png")

For a route that reuses the same DOM node, wait for a changed attribute, text value, or child count instead of waiting for presence alone.

Full-page and visual-settling considerations

save_screenshot() captures the current browser window. It does not automatically wait for front-end rendering, scroll through a page to trigger lazy loading, or verify that animations have stopped. Before capture, decide whether you need to:

  • Resize the window or set a consistent viewport.
  • Scroll to trigger lazy-loaded content, then wait for each required asset.
  • Disable or wait for transitions that would produce an intermediate frame.
  • Hide transient UI such as cookie dialogs if your test permits it.
  • Capture PNG bytes with get_screenshot_as_png() instead of writing a file.
png_bytes = driver.get_screenshot_as_png()
with open("page.png", "wb") as output:
    output.write(png_bytes)

Use a deterministic browser size and data state when comparing screenshots. A readiness marker should describe the content, not merely the passage of time.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common failures

TimeoutException while waiting for an element

  • Cause: The selector is wrong, the element is inside an iframe, the application entered an error state, or the timeout is shorter than the real load.
  • Fix: Inspect the live DOM, switch into the correct iframe when applicable, wait for an error marker separately, and choose a timeout based on the page’s allowed behavior.

The screenshot contains a spinner or empty panel

  • Cause: The wait targeted a container that exists before its data arrives.
  • Fix: Wait for the populated child, expected text, a ready attribute, or spinner invisibility.

The image is blank or partially decoded

  • Cause: Element visibility occurred before the image completed, the URL failed, or lazy loading was never triggered.
  • Fix: Scroll or otherwise trigger loading, then check complete and natural dimensions; also log failed resource requests if your test infrastructure supports it.

Different runs capture different frames

  • Cause: Animations, rotating content, asynchronous requests, or an arbitrary sleep.
  • Fix: Wait for a stable application marker, disable motion in test CSS where appropriate, and control test data and viewport size.

Navigation hangs before the explicit wait

  • Cause: A page-load timeout, redirect loop, blocked resource, or browser-level failure.
  • Fix: Set a page-load timeout, capture the exception and current URL, and investigate navigation separately from application readiness.

Or skip the browser setup

When you only need a clean rendered screenshot, ScreenshotNeo can handle the capture with one request. It removes cookie and consent banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and each response reports the result in X-Page-Verdict and X-Billed headers. Its MCP server lets AI agents such as Claude and Cursor call screenshot tools directly.

See the ScreenshotNeo website and API documentation for options including full-page capture, CSS-selector element shots, custom waits, JavaScript, headers, cookies, device presets, PDFs, signed links, asynchronous jobs, and bulk capture.

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

The free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account.

Practical reliability checklist

  • Identify the exact visual state required by the screenshot.
  • Use a stable, page-specific locator or readiness marker.
  • Wait after every click, submit, route change, and data refresh that affects the image.
  • Use explicit waits instead of a guessed sleep whenever a signal exists.
  • Do not mix implicit and explicit waits without understanding their combined timing.
  • Keep page-load and explicit-wait timeouts separate.
  • Verify image decoding and lazy-loaded content when they appear in the shot.
  • Set a deterministic viewport and account for animations and transient overlays.

Frequently Asked Questions

Should I always wait for document.readyState to be complete?

No. Use it when browser document readiness is the requirement. For dynamic applications, wait for the specific content or state that must appear in the screenshot.

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

What happens when an explicit wait expires?

Selenium raises a timeout exception. Capture diagnostics such as the URL, page source, and a failure screenshot, then verify the locator and application state.

Can Selenium take a screenshot while a page is still loading?

Yes. Screenshot methods capture the current window; synchronization is your responsibility. Calling one immediately after navigation can therefore produce an intermediate frame.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

More from the Wire

  1. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
  2. Cupertino desk5 min
    Apple Unveils AirPods Max 2: The Upgrade That Should Have Happened Years AgoAirPods Max 2 adds H2-powered audio features and Apple claims up to 1.5× more effective ANC, but its design, Smart Case, and 20-hour battery rating are unchanged. Wired lossless audio…
  3. Cupertino desk4 min
    Apple’s OLED Touch MacBooks Are Coming—but the Dynamic Island Is the Real GambleApple has not announced an OLED touchscreen MacBook, but reports point to high-end models arriving in late 2026 or early 2027. The reported Mac Dynamic Island could be useful, but…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.