How to Take a Selenium Screenshot of a Page with a CAPTCHA
Save the CAPTCHA state Selenium displays as a PNG, wait for the right UI, and use repeatable reCAPTCHA test keys for reliable tests.
In Selenium Python, save the current browser window as a PNG with driver.save_screenshot("captcha.png") after the CAPTCHA UI you want to document has rendered. Check the method’s Boolean return value and make sure the destination directory exists and is writable. This captures the current window; it does not promise a screenshot of the entire scrollable document. For repeatable tests on a site you own or are authorized to test, configure the CAPTCHA provider’s documented test keys rather than relying on a challenge appearing in every automated run.
Save the CAPTCHA page as a PNG
Install Selenium and make the browser driver available for your environment. Replace the placeholder URL with a test page you control. The example creates the output directory, navigates to the page, waits for a CAPTCHA-related element, writes the screenshot, and always quits the browser.
from pathlib import Path
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
output = Path("screenshots")
output.mkdir(parents=True, exist_ok=True)
driver = webdriver.Chrome()
try:
driver.get("https://your-test-site.example/captcha")
# Use a stable element from your own page or test integration.
WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".g-recaptcha"))
)
saved = driver.save_screenshot(str(output / "captcha.png"))
if not saved:
raise OSError("Selenium could not write the screenshot")
finally:
driver.quit()
In the code above, remove the accidental leading space before driver = webdriver.Chrome() if copying into a Python file; the line should align with output. Replace .g-recaptcha with a locator that exists in your application. A third-party challenge may render in a cross-origin frame or asynchronously, so a locator for your own page’s container or an explicit test-state marker is often more reliable than assuming the iframe is immediately available.
Selenium also offers driver.get_screenshot_as_file("screenshots/captcha.png"), which saves the current window as a PNG. Check its Boolean return just as you would for save_screenshot. The official [Selenium WebDriver API](https://www.selenium.dev/selenium/docs/api/py/) documents the screenshot methods.
Make the CAPTCHA state repeatable
Automated runs may not display an interactive challenge consistently. The appropriate solution for development and QA is the CAPTCHA provider’s test configuration, not a CAPTCHA-solving service. For Google reCAPTCHA, use the provider’s guidance for the version your application integrates:
| Integration | Test setup | What the screenshot can show |
|---|---|---|
| reCAPTCHA v2 | Google supplies test keys that always produce “No CAPTCHA” and pass verification requests. The widget displays a warning so the keys are not used for production traffic. | A stable widget state for UI and integration testing; the test configuration does not represent a production challenge. |
| reCAPTCHA v3 | Create a separate key for testing environments. Google notes that scores may not be accurate because v3 relies on real traffic. | The page UI, if any. v3 is score based, so there may be no visible challenge to photograph. |
See Google’s [automated testing guidance](https://developers.google.com/recaptcha/docs/faq#automated_test) and [v3 guide](https://developers.google.com/recaptcha/docs/v3). Use development and staging domains that match the key configuration. Google says localhost must be added to the allowed domains for local development; it advises separate development and production keys. Disabling domain validation carries a security risk and requires your server to verify the hostname or package itself ([domain validation guidance](https://developers.google.com/recaptcha/docs/domain_validation)).
Wait for the state you intend to capture
- Open the authorized test page. Use the intended development or staging key and domain.
- Wait for the relevant UI. Navigation completion alone does not guarantee an asynchronously loaded widget is ready. Wait for a stable element or test marker from your own application.
- Capture the current window. Call
save_screenshotorget_screenshot_as_fileafter the target state appears. - Check the write result. Fail the test if Selenium returns
False; verify the parent directory and permissions. - Assert success separately. A screenshot records browser output; it does not prove that backend CAPTCHA verification succeeded.
- Protect the artifact. Screenshots and logs can expose personal information, session details, or tokens. Store and share them according to your test-data practices.
Google says reCAPTCHA response tokens must be verified server-side within two minutes and can only be verified once. A screenshot cannot establish that this verification passed. Test the application’s server response or resulting application state independently ([response verification](https://developers.google.com/recaptcha/docs/verify)).
Choose an appropriate wait and capture scope
Wait for your application’s marker
Prefer a page-level condition that describes the state your test needs: a test banner, a submitted form result, or the container around the CAPTCHA widget. A fixed sleep may work for a quick local experiment, but it adds delay to every run and can still be too short on a slow run. An explicit wait with a bounded timeout is usually clearer: it proceeds as soon as the condition is true and gives a useful timeout failure when it never becomes true.
Do not try to read or manipulate a CAPTCHA provider’s cross-origin frame as a shortcut. For screenshot documentation, capture the browser state Selenium can see. For behavior tests, use the documented test keys and verify the app’s own outcome.
Current window versus full document
save_screenshot and get_screenshot_as_file are current-window screenshot methods. If the page scrolls, the result should not be described as a guaranteed full-page capture. Keep the target UI inside the viewport by setting a suitable window size before navigation or scrolling the relevant application element into view before saving. If you need a full-document image, choose a capture method that explicitly supports full-page capture and verify its behavior in your browser setup.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
save_screenshot returns False, or no PNG appears |
The path’s parent directory does not exist, the process cannot write there, or the path is invalid. | Create the directory first, use an explicit path, check permissions, and fail the test when the return value is false. |
| The PNG exists but the widget is missing | The screenshot ran before asynchronous rendering or before the desired test state. | Wait for a stable element or application marker that corresponds to the intended state, then capture. |
| The page displays “localhost is not in the list of supported domains” | The configured key does not allow localhost. | Add localhost to the development key’s allowed domains and keep production key configuration separate, as Google advises. |
| The challenge or result changes from run to run | The run depends on live risk signals or a production configuration. | Use Google’s v2 test keys for a repeatable v2 state, or a separate v3 testing key; do not expect v3 test scores to represent real traffic. |
| A screenshot appears successful, but the application rejects the CAPTCHA | An image of the UI is not evidence of successful server-side verification; a token can expire or already have been used. | Assert the application’s verification result. For Google reCAPTCHA, request a fresh token when necessary and verify it within two minutes, once. |
| The screenshot is cropped or omits content below the fold | The screenshot method captures the current window. | Set the viewport and scroll position intentionally, or use a capture approach with explicit full-page support. |
Performance, reliability, and cost
For a single screenshot, the main runtime is usually page navigation and waiting for the selected state; the image write itself is one operation. Avoid unnecessarily long fixed sleeps. Use explicit waits with a timeout that fits your test environment, and keep the screenshot focused on the state the test needs.
Reliability comes from separating three checks: page readiness, screenshot-file creation, and CAPTCHA/application acceptance. A successful PNG only confirms that Selenium wrote an image of the current window. It does not guarantee that the page loaded correctly or that a backend accepted a response token. Use test keys and assert each condition independently.
Selenium’s screenshot call does not introduce a separate screenshot API charge. Your execution cost depends on the browser and test infrastructure you run. If you need hosted website captures without maintaining browser setup, ScreenshotNeo offers a one-request screenshot API; its billing and plan details are below.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. Use it when you need a page image without setting up Selenium and a browser driver. It returns PNG, JPEG, WebP, or PDF from a GET request. Its capture flow accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step 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.
For a normal public page capture, the documented call is:
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}`);
See the ScreenshotNeo API documentation for request options. The API supports full-page capture, element selection, viewport and device presets, retina scale, custom CSS and JavaScript, wait conditions, cookies and headers, request blocking, caching, signed links, asynchronous jobs, bulk capture, and more. Its MCP server gives AI agents tools for screenshots, page info, and PDF capture. Plans include 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
FAQ
Does a screenshot prove the CAPTCHA passed?
No. It records visible browser output. Assert the application’s server-side verification result separately.
Can I screenshot reCAPTCHA v3 challenge text?
Often there is no interactive challenge: v3 is score based. Capture the page UI if useful, and test the score-based integration separately.
Can Selenium save the screenshot as JPEG?
The Selenium screenshot methods described here save PNG files. If another format is required, convert the resulting image with an image-processing library.
Why use a test key instead of a production key?
Test keys make the intended development behavior repeatable and keep automated checks separate from production configuration. Google specifically warns that its v2 test keys are for testing, not production traffic.


