ScreenshotNeo

BlogHow-to

How to Wait for a Specific Element Before Taking a Selenium Screenshot

Wait for the exact page state your screenshot needs, then capture either the target element or the whole viewport with Selenium.

By the ScreenshotNeo team4 October 20264 min read

Use a Selenium explicit wait for the exact element state your screenshot requires, then pass the returned element to element.screenshot(). For example, wait until the element is visible before saving a PNG:

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

locator = (By.CSS_SELECTOR, "#target")
element = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located(locator)
)
element.screenshot("target.png")

The 10-second timeout is an example; choose a limit appropriate for your application and test environment. Element screenshots contain the target element. To capture the browser viewport instead, wait for the element and call driver.save_screenshot("page.png").

1. Set up Selenium and load the page

Install the Python binding with pip. Selenium Manager can manage browser drivers for supported setups when you create a driver instance.

python -m pip install selenium
from selenium import webdriver

with webdriver.Chrome() as driver:
    driver.get("https://example.com")
    # Add the explicit wait and screenshot code here.

Run this where the browser can start. In a headless or remote test environment, make sure the browser is installed, its dependencies are available, and your Selenium setup is configured for that environment.

2. Wait for the right condition

A navigation reaching its page-load state does not guarantee that JavaScript-driven content has appeared. Wait on the state that makes the intended screenshot meaningful:

Condition Use it when Example
Presence The node must exist in the DOM, even if it is not displayed yet. EC.presence_of_element_located(locator)
Visibility The target should be displayed and have non-zero dimensions. EC.visibility_of_element_located(locator)
Visible text A particular text value indicates that rendering or data loading is complete. EC.text_to_be_present_in_element(locator, "Ready")
Application state Your app exposes a specific marker, status, or attribute for completion. Use a custom wait condition that checks that marker.

Presence alone is not enough if the element is hidden, covered, or still awaiting content. Visibility is a better starting condition for an element screenshot. If the application updates the element after displaying it, wait for the relevant text or state too.

3. Capture the element or the viewport

Capture just the element

WebDriverWait.until() returns the truthy result from its condition. Visibility conditions return the matched element, so you can use that object directly:

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

locator = (By.CSS_SELECTOR, "#target")
element = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located(locator)
)
element.screenshot("target.png")

The element screenshot API saves a PNG. Selenium also provides element screenshot methods for PNG bytes and base64 output if you need to store or process the data in memory.

Capture the whole viewport

Use a driver-level screenshot method when the output should show the current browser viewport, not a crop of the element. Keep the explicit wait so the target is ready before the capture:

element = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "#target"))
)
driver.save_screenshot("viewport.png")

The element variable confirms the wait succeeded; the driver method captures the viewport. These are distinct outputs. Do not assume an element screenshot is a full-page screenshot.

4. Use a stronger application-specific readiness check

When visibility happens before the useful content is ready, wait for an app-specific signal. For example, if a result element starts with a loading label and changes to a known final label:

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

locator = (By.CSS_SELECTOR, "#result")
wait = WebDriverWait(driver, 15)
wait.until(EC.visibility_of_element_located(locator))
wait.until(EC.text_to_be_present_in_element(locator, "Results loaded"))
element = driver.find_element(*locator)
element.screenshot("results.png")

If the application publishes a stable completion attribute, check that attribute instead of relying on text. A custom condition can return the element once the state is ready:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

def element_ready(driver):
    element = driver.find_element(By.CSS_SELECTOR, "#result")
    if element.is_displayed() and element.get_attribute("data-state") == "ready":
        return element
    return False

element = WebDriverWait(driver, 15).until(element_ready)
element.screenshot("results.png")

Use a completion signal that reflects the content you intend to capture. Waiting for an unrelated element or merely for navigation completion can still produce an early image.

5. Choose timeout and polling behavior

WebDriverWait takes a timeout and an optional polling interval. Its default polling interval is 0.5 seconds, and by default it ignores NoSuchElementException while checking. until() returns the condition’s truthy result or raises TimeoutException when the condition does not become true in time.

wait = WebDriverWait(driver, timeout=12, poll_frequency=0.25)
element = wait.until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "#target"))
)

Pick a timeout based on expected page behavior and the runtime environment. A shorter poll can check more frequently but does not make a slow application ready sooner. Avoid adding a long fixed sleep after the wait: it delays every successful run without proving a stronger condition.

Selenium warns: “Do not mix implicit and explicit waits.” Combining them can produce unpredictable wait durations. Prefer explicit waits for this workflow and avoid setting an implicit wait alongside them.

6. Troubleshoot common failures

Symptom Likely cause Fix
TimeoutException The locator is wrong, the target never reaches the requested state, or the timeout is too short for the environment. Check the selector against the live DOM, confirm the expected state can occur, and adjust the timeout to the application’s real behavior.
NoSuchElementException outside the wait Code looks up the element before it exists, or uses a different locator from the wait. Use the element returned by until(), or perform the lookup after the wait with the same locator.
Wait succeeds but screenshot is blank or incomplete Presence or visibility became true before the application finished populating the element. Wait for expected text, a loading-state transition, or a stable app-specific readiness marker.
Screenshot is of the wrong area The code used an element screenshot when it needed the viewport, or vice versa. Use element.screenshot() for the element crop and driver.save_screenshot() for the viewport.
Element becomes stale during a wait or after it A client-side rerender replaced the DOM node. Wait for the final state after the rerender and reacquire the element; do not keep using a stale element reference.
Element screenshot raises an error because it is not visible The node exists but is hidden, outside the expected display state, or changed between the wait and capture. Wait for visibility and, if the page rerenders, reacquire the element immediately before capture.
Driver or browser startup fails The browser, driver, or runtime dependencies are unavailable or incompatible in the execution environment. Check the installed browser and Selenium setup, then configure the driver for the local, container, or remote environment.

7. Performance, reliability, and cost

  • Performance: Condition-based waits proceed as soon as their condition is true, while fixed sleeps always consume the full delay. Choose a condition that is neither weaker nor more demanding than the screenshot requires.
  • Reliability: A meaningful app readiness signal is more reliable than assuming page navigation means dynamic content is done. Keep selectors and state markers tied to the page behavior under test.
  • Cost: Selenium itself is an open-source browser automation project, but running it still uses your browser and compute environment. For a hosted screenshot API, account for its plan limits and whether unsuccessful captures are billed.

8. Or skip the browser setup

If your goal is a screenshot rather than controlling a browser session, ScreenshotNeo provides a website screenshot API. Its API documentation describes the request 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}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, and cache hits are not billed; responses report the page verdict and billing status in headers. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

9. FAQ

Does waiting for visibility guarantee that all images and fonts have loaded?

No. Visibility describes the target element’s display state. If the screenshot depends on other assets or later application work, wait for the relevant app-specific readiness signal.

Can I use a CSS selector or XPath?

Yes. Selenium locators can use CSS selectors, XPath, and other supported locator strategies. Keep the same locator for the wait and any follow-up lookup.

Why not use time.sleep()?

A sleep waits a fixed duration regardless of page state. An explicit wait continues when the condition is met and reports a timeout if it is not.

Does this capture the full page?

No. The element screenshot captures the target element, and the driver screenshot captures the viewport. They are not full-page capture instructions.

Sources