How to Capture a Full-Page Screenshot in Selenium WebDriver Using Java
Capture an entire webpage in Selenium Java with Firefox, understand Chrome DevTools limits, and avoid common full-page screenshot failures.
Use FirefoxDriver’s dedicated full-page method when you need a complete document screenshot in Selenium Java: driver.getFullPageScreenshotAs(OutputType.FILE). Selenium’s generic TakesScreenshot command captures the visual viewport, so it is not a reliable cross-browser synonym for a full-document image.
This guide shows the Firefox implementation, the normal viewport and element alternatives, a version-sensitive Chrome DevTools approach, content-waiting techniques, troubleshooting, and a hosted option when you do not want to maintain browser drivers.
1. The recommended Java implementation: Firefox full-page capture
Selenium’s FirefoxDriver exposes getFullPageScreenshotAs(OutputType<X>), documented as capturing the full page. The output type determines whether Selenium returns a temporary file, bytes, or another representation. FirefoxDriver API documentation
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.firefox.FirefoxDriver;
public class FullPageScreenshot {
public static void main(String[] args) throws Exception {
FirefoxDriver driver = new FirefoxDriver();
try {
driver.get("https://example.com");
File temporaryScreenshot = driver.getFullPageScreenshotAs(OutputType.FILE);
Path destination = Path.of("example-full-page.png");
Files.copy(
temporaryScreenshot.toPath(),
destination,
StandardCopyOption.REPLACE_EXISTING
);
System.out.println("Saved " + destination.toAbsolutePath());
} finally {
driver.quit();
}
}
}
Make sure Firefox and the matching Selenium setup are installed. Selenium Manager can obtain browser drivers in current Selenium distributions; managed CI images can also provide the driver explicitly.
Why copy the returned file?
OutputType.FILE returns a temporary file. Copy it to a location you control before the driver session ends or the temporary file is cleaned up.
2. What the generic Selenium screenshot command captures
The standard WebDriver screenshot command is defined as a capture of the top-level browsing context’s visual viewport. Selenium’s Java example is:
import java.io.File;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
WebDriver driver = new FirefoxDriver();
try {
driver.get("https://example.com");
File viewportShot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
} finally {
driver.quit();
}
This is useful for the currently visible browser area, but it does not promise the entire document. See the W3C WebDriver screenshot specification and Selenium’s TakesScreenshot API.
Element screenshots are different
You can capture one element with Selenium’s element screenshot API:
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.OutputType;
WebElement article = driver.findElement(By.cssSelector("article"));
File articleShot = article.getScreenshotAs(OutputType.FILE);
An element screenshot is scoped to that element. It is not a full-document capture.
Maximize and fullscreen do not make a full-page image
driver.manage().window().maximize() and driver.manage().window().fullscreen() change window dimensions. They do not change the standard screenshot command’s defined scope from the visual viewport to the entire document.
3. Chrome: use the matching Selenium DevTools binding
Chrome can capture beyond the viewport through the DevTools Page.captureScreenshot command. Selenium’s Java DevTools bindings are versioned, so the method signature and module must match the Selenium and browser versions installed. The cited Selenium 4.22.0 / CDP v124 API includes a captureBeyondViewport parameter; do not treat that generated API as an evergreen cross-version call.
The exact imports and return type vary by DevTools module. Start by adding the module that matches your Selenium version, then consult that module’s Page.captureScreenshot documentation:
// Illustrative shape only: use the Page class and method from your
// installed Selenium DevTools version.
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
// In the matching CDP module, call Page.captureScreenshot with
// captureBeyondViewport=true and write the returned Base64 data to a file.
// The generated method signature is version-specific.
For a stable, documented Java full-page method with less version coupling, use FirefoxDriver’s API. If you must use Chrome, pin and document the Selenium DevTools module alongside the browser version in your build.
4. Wait for the page before capturing
A screenshot call does not guarantee that application data, fonts, images, or lazy content has finished rendering. Wait for the condition that matters to your page.
Wait for a key element
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("main article")
));
Wait for document readiness
new WebDriverWait(driver, Duration.ofSeconds(30)).until(
d -> ((org.openqa.selenium.JavascriptExecutor) d)
.executeScript("return document.readyState")
.equals("complete")
);
document.readyState only describes document loading. A single-page application may still be fetching data after it becomes complete, so prefer a selector or application-specific readiness signal when possible.
Lazy-loaded images
Full-page support does not prove that every offscreen lazy image has loaded. If the page uses lazy loading, scroll through it and wait for images before capture. This is page-specific preparation:
import org.openqa.selenium.JavascriptExecutor;
JavascriptExecutor js = (JavascriptExecutor) driver;
long previousHeight = 0;
for (int i = 0; i < 30; i++) {
long height = ((Number) js.executeScript(
"return Math.max(document.body.scrollHeight, " +
"document.documentElement.scrollHeight);"
)).longValue();
js.executeScript("window.scrollTo(0, arguments[0]);", height);
Thread.sleep(300);
if (height == previousHeight) break;
previousHeight = height;
}
js.executeScript("window.scrollTo(0, 0);");
Use an explicit wait instead of a fixed sleep when your application exposes a reliable completion condition. Scrolling can trigger more content, so repeat until the document height stops changing or your own page limit is reached.
5. A complete reusable helper
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public final class ScreenshotHelper {
public static Path capture(String url, String output) throws Exception {
FirefoxDriver driver = new FirefoxDriver();
try {
driver.get(url);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("body")));
File temporary = driver.getFullPageScreenshotAs(OutputType.FILE);
Path destination = Path.of(output);
Files.copy(temporary.toPath(), destination, StandardCopyOption.REPLACE_EXISTING);
return destination;
} finally {
driver.quit();
}
}
public static void main(String[] args) throws Exception {
System.out.println(capture("https://example.com", "page.png"));
}
}
6. Common errors and fixes
| Error or symptom | Cause | Fix |
|---|---|---|
getFullPageScreenshotAs is missing |
The variable is typed as generic WebDriver, or the active driver is not FirefoxDriver. |
Use a FirefoxDriver reference for this method, or use the matching browser-specific API. |
| Only the visible area is saved | You called TakesScreenshot.getScreenshotAs. |
Use Firefox’s full-page method or the version-matched Chrome DevTools command. |
| Screenshot file disappears | OutputType.FILE points to a temporary file. |
Copy it immediately to your destination path. |
| Blank or incomplete page | Capture ran before client-side rendering finished, or navigation failed. | Wait for a meaningful selector, verify the URL and page state, and capture after the application is ready. |
| Missing images below the fold | Images are lazy-loaded only after scrolling. | Scroll through the document, wait for image loads, then capture. |
| Chrome DevTools compile error | The example targets a different CDP/Selenium module than the installed version. | Use the DevTools module matching your Selenium release and browser, then check that version’s generated Page.captureScreenshot signature. |
| Driver session cannot start | Browser installation, driver resolution, permissions, or CI display configuration is wrong. | Confirm the browser exists, update Selenium, inspect Selenium Manager logs, and configure headless mode for a display-less runner. |
| Sticky header appears repeatedly | The page’s fixed or sticky element is part of the rendered document during capture. | Hide or restyle it with test-only JavaScript/CSS before capture, if your output requirements allow that. |
| Very tall image fails or is slow | Large dimensions require more browser memory and image encoding time. | Split the page into sections, reduce content, or use a hosted screenshot service with output controls. |
7. Reliability and performance checklist
- Pin Selenium and browser versions in CI when using DevTools APIs.
- Use explicit waits tied to application state instead of arbitrary delays.
- Set a page-load timeout and handle navigation exceptions.
- Use a fresh driver for isolated jobs; always call
quit()in afinallyblock. - Scroll and verify lazy content when the page depends on viewport intersection.
- Keep output paths unique in parallel jobs to avoid overwriting files.
- Record the URL, browser version, Selenium version, viewport, and failure reason with each artifact.
- Expect taller pages to consume more memory and take longer to encode than viewport captures.
8. Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF, with options for full-page capture, lazy-image loading, custom viewports, device presets, retina scale, waits, CSS and JavaScript, cookies, headers, geolocation, caching, signed links, asynchronous jobs, and bulk capture. See the ScreenshotNeo API documentation for the current parameter details.
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,
)
r.raise_for_status()
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 failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);
ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and response headers report the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
9. Cost and operational choices
Running Selenium yourself means paying for browser hosts, CI minutes, storage, driver maintenance, and engineering time. It gives you direct control over browser state and network access. A hosted API shifts browser execution and scaling to the service and can be simpler for scheduled or high-volume captures.
ScreenshotNeo bills only clean shots. Its plans are Free: 1,000/month; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; and Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is available on every plan.
10. FAQ
Does Selenium’s default screenshot include the whole HTML document?
No. The standard command is defined for the visual viewport. Use FirefoxDriver’s full-page method or a matching browser-specific API.
Can I call Firefox’s full-page method through WebDriver?
Call it on a FirefoxDriver reference, because the method is FirefoxDriver-specific.
Is a full-page screenshot the same as an element screenshot?
No. An element screenshot captures one WebElement; a full-page screenshot captures the document.
Should I use Chrome DevTools for every browser?
No. DevTools bindings are browser and version specific. Select the module that matches your installed Selenium and browser versions.
Will full-page capture load every lazy image?
Not automatically in every application. Scroll and wait for the page’s lazy-loading behavior before capturing.
What is the simplest managed alternative?
Use ScreenshotNeo’s single request when you want full-page capture without provisioning Selenium, and start with its free 1,000-shot monthly plan.


