How to Take Screenshots in Selenium 4
Capture Selenium 4 viewports, elements, and full pages with reliable Java, Python, and Node.js code, plus fixes for common failures.
Short answer: Selenium 4 exposes screenshots through WebDriver. In Java, cast the driver or a WebElement to TakesScreenshot and call getScreenshotAs(OutputType.FILE) or BASE64. In Python, call driver.save_screenshot('path.png') or get_screenshot_as_file, or request PNG bytes/Base64 when you need the image in memory. A normal driver screenshot is the current viewport; element and full-page captures are separate capabilities.
Choose the capture you need
| Goal | API | Output | Support note |
|---|---|---|---|
| Current browser viewport | Driver screenshot | PNG file, bytes, or Base64 | Available through the WebDriver screenshot API. |
| One component | WebElement screenshot | PNG file or Base64 | Locate the element first; implementation support can vary. |
| Entire document | Firefox full-page methods | PNG file | Firefox Python binding documents dedicated full-page methods. Other browsers and bindings may differ. |
Java: save a Selenium 4 screenshot
The Java API’s TakesScreenshot interface supports drivers and elements. Navigate, wait for the state you want to document, then save the returned file.
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class ViewportScreenshot {
public static void main(String[] args) throws Exception {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
wait.until(ExpectedConditions.titleContains("Example"));
Path output = Path.of("artifacts", "example.png");
Files.createDirectories(output.getParent());
File source = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Files.copy(source.toPath(), output, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
System.out.println("Wrote " + output.toAbsolutePath());
} finally {
driver.quit();
}
}
}
OutputType.FILE gives you a temporary file that you copy to a stable artifact path. The API also supports OutputType.BASE64; see the Java TakesScreenshot API.
Java: capture one element
WebElement card = new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".pricing-card")));
String base64 = ((TakesScreenshot) card).getScreenshotAs(OutputType.BASE64);
Files.writeString(Path.of("artifacts", "pricing-card.b64"), base64);
Element screenshots describe the element’s rendered box. If the browser or binding does not implement them, Selenium can raise UnsupportedOperationException or WebDriverException; use a driver screenshot and crop as a fallback.
Python: save, return bytes, or return Base64
Python’s file methods return True on success and False on an I/O error. They do not create missing directories.
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
out = Path('artifacts')
out.mkdir(parents=True, exist_ok=True)
driver = webdriver.Chrome()
try:
driver.get('https://example.com')
WebDriverWait(driver, 15).until(lambda d: d.title == 'Example Domain')
target = out / 'example.png'
ok = driver.save_screenshot(str(target))
if not ok:
raise OSError(f'Selenium could not write {target}')
finally:
driver.quit()
Python: in-memory forms
png_bytes = driver.get_screenshot_as_png()
base64_text = driver.get_screenshot_as_base64()
Path('artifacts/page.png').write_bytes(png_bytes)
Path('artifacts/page.b64').write_text(base64_text, encoding='ascii')
get_screenshot_as_file(path) is an equivalent PNG-file method. Use bytes for image processing or uploads, and Base64 for HTML reports.
Python: element and Firefox full-page screenshots
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
hero = WebDriverWait(driver, 15).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, 'main'))
)
hero.screenshot('artifacts/main.png')
firefox_driver = webdriver.Firefox()
try:
firefox_driver.get('https://example.com/long-page')
firefox_driver.get_full_page_screenshot_as_file('artifacts/full-page.png')
finally:
firefox_driver.quit()
Firefox’s Python binding documents get_full_page_screenshot_as_file and save_full_page_screenshot. Do not assume the same method exists in every browser and binding.
JavaScript (Node.js) example
const { Builder } = require('selenium-webdriver');
const fs = require('node:fs/promises');
(async () => {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com');
const pngBase64 = await driver.takeScreenshot();
await fs.mkdir('artifacts', { recursive: true });
await fs.writeFile('artifacts/example.png', Buffer.from(pngBase64, 'base64'));
} finally {
await driver.quit();
}
})();
Reliable screenshot workflow
- Navigate to the target URL.
- Wait for a title, selector, or application condition instead of relying on a fixed sleep.
- Choose driver, element, or browser-specific full-page scope.
- Create directories and use unique, stable artifact names.
- Capture and verify Python’s Boolean result; handle Java WebDriver exceptions.
- Call
quit()in afinallyblock.
Frames, windows, and scrolling
A screenshot reflects the current browsing context. Switch to the intended window and iframe before locating an element. Scroll content into view for a viewport capture; scrolling does not create a full-document image.
Options and capture details
- Set a fixed viewport or browser window size for deterministic responsive layouts.
- Keep browser/device scale settings fixed for visual regression.
- Use files for CI artifacts, bytes for image processing, and Base64 for reports.
- Wait for visibility and animation completion; mask dynamic regions when comparing images.
- Establish cookies or storage in the same driver session before capture.
- Protect screenshots because they may contain secrets or personal data.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Python returns False |
Missing directory, unwritable path, or I/O error. | Create the directory, use an absolute path, and check permissions. |
NoSuchElementException |
Element is not ready or the driver is in another frame. | Use an explicit wait and switch to the correct iframe. |
| Blank or partial image | Capture occurred before rendering completed. | Wait for a meaningful application state. |
| Unsupported-operation error | Requested target is not implemented by that driver. | Use a driver screenshot or a supported binding method. |
| Only visible content appears | Driver screenshots are viewport captures. | Use Firefox full-page support or a validated scroll-and-stitch workflow. |
| Wrong tab | Focus remained on another window handle. | Select the intended handle before capture. |
| Intermittent visual diffs | Fonts, animations, lazy content, or timing vary. | Fix viewport settings, wait for stable state, preload fonts, and mask dynamic regions. |
Performance, reliability, and cost
A screenshot requires a live browser, navigation, JavaScript execution, and image encoding. Reuse a driver for related captures, avoid unnecessary full-page work, and write artifacts asynchronously where practical. Parallel browsers improve throughput but increase CPU, memory, and file-collision risk.
For reliable CI, pin browser and driver versions, retain the first failure artifact, and retry only transient navigation failures. Selenium itself has no screenshot-service fee; you pay for machines, browser sessions, storage, and CI minutes.
Or skip the browser setup
If you need an image or PDF from a URL, ScreenshotNeo provides a single GET endpoint. See the API documentation.
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}`);
ScreenshotNeo accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and billing status. Its MCP server lets AI agents take screenshots, and 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Does Selenium save JPEG or WebP directly?
The documented methods return PNG files, bytes, or Base64. Convert the PNG afterward if needed.
Can I screenshot a hidden element?
Usually no useful pixels are produced. Make it visible and wait for its final state.
Why is my full-page method missing?
Full-page capture is browser- and binding-specific. Check the current API for your chosen browser and language.
Should I use a fixed sleep?
Prefer an explicit wait for the state that matters. Fixed sleeps are slower when pages are fast and flaky when pages are slow.


