ScreenshotNeo

BlogHow-to

How to Capture a Selenium Screenshot After Clicking a Button on a Web Page

Click a button, wait for the page’s resulting state, then capture the current window with Selenium. Includes runnable Python, cURL, Node.js, and ScreenshotNeo options.

By the ScreenshotNeo team4 October 20268 min read

To capture the page after a button click with Selenium, click the button, explicitly wait for the result you expect, and then call save_screenshot(). The click returning does not guarantee that JavaScript-driven page updates have finished.

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

button = driver.find_element(By.ID, "open-panel")
button.click()

# Wait for a post-click state that proves the page is ready to capture.
WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located((By.ID, "result-panel"))
)

driver.save_screenshot("after-click.png")

Replace the example locator and wait condition with ones that match the page. The timeout is an example, not a universal recommendation. See the Selenium waits guide, element interactions documentation, and Python WebDriver API.

1. Use a wait that confirms the click worked

Button clicks commonly trigger asynchronous JavaScript updates. WebDriver may finish the click command before the page has revealed a panel, updated text, or finished loading data. Waiting only for navigation readiness does not establish that the application state changed by the click is ready.

Choose a condition that represents the state the screenshot should show:

Expected result Useful condition Example
A hidden panel appears Visibility of the panel EC.visibility_of_element_located((By.ID, "result-panel"))
New content is inserted Presence of the content element EC.presence_of_element_located((By.CSS_SELECTOR, ".result"))
An existing label changes Expected text appears EC.text_to_be_present_in_element((By.ID, "status"), "Complete")
A loading overlay goes away Overlay becomes invisible EC.invisibility_of_element_located((By.CSS_SELECTOR, ".loading"))
A button becomes enabled after work Element is clickable EC.element_to_be_clickable((By.ID, "continue"))

Explicit waits poll a named condition until it succeeds or the timeout expires. They are generally more reliable and efficient than a fixed sleep: a sleep may be too short on a slow run or waste time when the page is already ready. Avoid mixing implicit and explicit waits because Selenium warns that doing so can make total timeout durations unpredictable.

2. Complete runnable Python example

This example starts Chrome, opens a page, clicks a button, waits for the resulting panel, saves a screenshot, and closes the browser. Set PAGE_URL and the selectors to match your application. Selenium Manager can manage the browser driver for supported setups; install Selenium and have a compatible browser available.

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

PAGE_URL = "https://example.com"
BUTTON = (By.ID, "open-panel")
RESULT = (By.ID, "result-panel")

options = webdriver.ChromeOptions()
# Uncomment for a headless browser session:
# options.add_argument("--headless=new")

driver = webdriver.Chrome(options=options)
try:
    driver.get(PAGE_URL)
    wait = WebDriverWait(driver, 10)

    wait.until(EC.element_to_be_clickable(BUTTON)).click()
    wait.until(EC.visibility_of_element_located(RESULT))

    if not driver.save_screenshot("after-click.png"):
        raise RuntimeError("WebDriver did not save the screenshot")
finally:
    driver.quit()

save_screenshot() returns a success boolean. The screenshot API captures the current window. If you need the PNG bytes in memory instead of a file, use get_screenshot_as_png():

png_bytes = driver.get_screenshot_as_png()
with open("after-click.png", "wb") as image_file:
    image_file.write(png_bytes)

The documented method describes a screenshot of the current window; do not assume it produces one image of the entire scrollable page. For full-page output, use a capture method that explicitly supports it or capture and assemble the page with an approach verified for your browser.

3. Pick locators that survive page changes

Prefer a stable ID or an application-owned attribute such as a test identifier. Use a CSS selector or accessible locator appropriate to the markup when no stable ID exists. Avoid positional selectors tied to a page’s incidental layout: adding another button can silently change which element is clicked.

If the button is inside an iframe, switch to that frame before locating it, then switch back if later steps need the top-level page:

frame = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "iframe.payment")))
driver.switch_to.frame(frame)
wait.until(EC.element_to_be_clickable((By.ID, "open-panel"))).click()
wait.until(EC.visibility_of_element_located((By.ID, "result-panel")))
driver.save_screenshot("inside-frame-state.png")
driver.switch_to.default_content()

For a button in a new tab or window, wait for the new window handle and switch to it before waiting for its page state and capturing. A screenshot is taken from the current browsing context.

4. Make the captured state deterministic

A useful screenshot needs more than a successful click. Match the wait to the page transition and control other changing inputs where necessary:

  • Wait for a new result or changed text, not merely for the clicked button to remain present.
  • If the page shows a spinner, wait for the relevant content to appear and, when appropriate, for the spinner to disappear.
  • For animations, wait for a stable application state or disable animations in a test-only stylesheet before capture.
  • Set a consistent viewport when screenshot dimensions matter: driver.set_window_size(1365, 900).
  • Use predictable test data and authenticated test accounts when the resulting content depends on user state.
  • Capture after any consent dialog or other overlay has been handled if the target image should show the underlying page.

Do not use a long fixed sleep as the standard synchronization mechanism. If a page offers no meaningful condition, a short bounded delay can be a last resort, but it is less reliable than observing a page state.

5. Click interception and other interaction edge cases

Selenium scrolls an element into view and checks that it is interactable before clicking. The click targets the element’s center. If another element covers that point, Selenium can report an element-click-intercepted error. Inspect overlays, sticky headers, modal layers, and animations; wait for the obstruction to disappear or close it through the intended UI flow.

Use element_to_be_clickable when the control may initially be hidden or disabled, but remember that being clickable does not prove that the click’s asynchronous result is complete. Wait for the result separately. If the click itself causes navigation, wait for the relevant URL or page element after clicking before saving the screenshot.

6. Troubleshooting

Symptom Likely cause Fix
TimeoutException while waiting The selector is wrong, the result never appeared, or the timeout is shorter than this environment needs. Check the locator and page state in the browser; wait for the actual post-click result and choose a timeout appropriate to the application.
ElementClickInterceptedException An overlay or another element covers the button’s center. Identify the covering element, wait for it to disappear or dismiss it, then retry the intended interaction.
ElementNotInteractableException The element is hidden, disabled, or otherwise not ready for interaction. Wait until it is visible and enabled; confirm that the locator identifies the interactive control rather than a wrapper.
Screenshot shows the old state The capture happened before the JavaScript update completed, or the wait checked a condition that was already true before the click. Wait for a condition that changes as a result of this click, such as new text, a newly visible panel, or a loading indicator disappearing.
Screenshot file is missing or empty The save result was not checked, the process lacks write access, or the path is not where expected. Check the boolean returned by save_screenshot(), use an explicit path, and ensure its directory exists and is writable.
Wrong frame or tab captured The driver is still in a frame or window other than the intended target. Switch to the intended frame or window before capture; verify the active page and restore the default content when finished.
Image dimensions are unexpected The browser window or viewport differs from the expected dimensions. Set the window size before capture and account for browser chrome when interpreting window dimensions.
Driver or browser startup failure The browser is missing, incompatible, or cannot start in the current environment. Install a supported browser, check Selenium and browser versions, and configure headless or container dependencies for the runtime.

7. Performance, reliability, and cost

Explicit waits improve both speed and reliability: they proceed as soon as the required state is observed and stop with a useful timeout if it never arrives. Keep the condition specific enough to avoid capturing a stale or unrelated element. Reuse a browser session for a sequence of captures when isolation requirements allow it; starting a new browser for every screenshot adds startup time. Always close the session in a finally block so failures do not leave browser processes running.

For parallel jobs, give each worker its own WebDriver session and output path. Sharing one driver between concurrent tasks can make clicks, active tabs, and screenshots interfere. ScreenshotNeo charges only for clean shots; bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers.

8. Or skip the browser setup

If you need a screenshot of a URL without running Selenium yourself, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF. It captures a URL’s page; it does not execute your Selenium click flow, so use Selenium when the screenshot specifically depends on a button interaction.

See the ScreenshotNeo API documentation. cURL example:

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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write("shot.webp", new Uint8Array(await res.arrayBuffer()));

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

9. Frequently asked questions

Can I save the screenshot without writing a file first?

Yes. Call driver.get_screenshot_as_png() to receive PNG bytes, then store or process them in memory.

Does save_screenshot() capture the whole page?

The documented screenshot method captures the current window. It does not promise a single image of all scrollable content.

Should I use JavaScript to click the button?

Use Selenium’s normal element click for user-like interaction. Consider JavaScript only when the application or test has a specific reason; it can bypass interactability behavior that the normal click checks.

What should the explicit wait timeout be?

Set it based on the expected response time and variability of your application and test environment. The example’s ten seconds is illustrative.