ScreenshotNeo

BlogHow-to

Use Java Selenium to Capture a Webpage Screenshot After Scrolling to the Bottom

Scroll to the bottom with Java Selenium, wait for lazy content, and save a screenshot. Learn what the capture includes and how to handle long pages reliably.

By the ScreenshotNeo team4 October 20267 min read

To capture a screenshot after scrolling to the bottom with Java Selenium, use JavascriptExecutor to scroll the page, wait for any content that loads near the bottom, then use TakesScreenshot to save the image. The example below captures the browser’s screenshot at that point. A bottom scroll does not guarantee that every browser and driver will stitch the entire document into one image.

1. Add Selenium and create a browser session

This example uses Maven and ChromeDriver. Selenium 4 can manage compatible browser drivers through Selenium Manager when the browser is installed. If your environment manages drivers separately, configure the driver path or service using your usual setup.

<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-java</artifactId>
  <version>4.27.0</version>
</dependency>

Use the Selenium version already approved for your project; check its official release information before pinning or upgrading it. The code uses Java 11 or later for Path.of.

2. Scroll to the bottom and save a screenshot

This minimal runnable example navigates to a page, scrolls to the current document bottom, takes the driver screenshot, copies it to a named PNG file, and always closes the browser session.

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class ScreenshotAfterScroll {
    public static void main(String[] args) throws IOException {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("https://example.com");

            JavascriptExecutor js = (JavascriptExecutor) driver;
            js.executeScript("window.scrollTo(0, document.body.scrollHeight)");

            File screenshot = ((TakesScreenshot) driver)
                    .getScreenshotAs(OutputType.FILE);
            Files.copy(screenshot.toPath(), Path.of("page-bottom.png"),
                    StandardCopyOption.REPLACE_EXISTING);
        } finally {
            driver.quit();
        }
    }
}

Replace https://example.com with the page you need. executeScript runs in the currently selected frame or window. The Selenium Java API describes TakesScreenshot as the screenshot interface; OutputType.FILE gives you a temporary file that you should copy to a destination you control. See the [Selenium screenshot documentation](https://www.selenium.dev/documentation/webdriver/interactions/) and [JavascriptExecutor API](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html).

3. Wait for lazy-loaded content

Some pages append images or other content only when the browser approaches them. A single jump to the current bottom can miss content farther down if the page grows after the jump. Scroll in increments, wait for a meaningful condition if the site exposes one, and stop when the document height remains stable. Always bound the loop so an endlessly growing feed cannot run forever.

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;

public final class ScrollToBottom {
    private ScrollToBottom() {}

    public static void scrollUntilStable(WebDriver driver) throws InterruptedException {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        long previousHeight = -1;
        int stableRounds = 0;
        int maxRounds = 30;

        for (int round = 0; round < maxRounds; round++) {
            long height = ((Number) js.executeScript(
                    "return document.documentElement.scrollHeight"
            )).longValue();

            js.executeScript("window.scrollTo(0, arguments[0])", height);
            Thread.sleep(500); // Replace with a condition wait when possible.

            long newHeight = ((Number) js.executeScript(
                    "return document.documentElement.scrollHeight"
            )).longValue();

            if (newHeight == previousHeight || newHeight == height) {
                stableRounds++;
                if (stableRounds >= 2) {
                    return;
                }
            } else {
                stableRounds = 0;
            }
            previousHeight = newHeight;
        }
    }
}

Call ScrollToBottom.scrollUntilStable(driver) after navigation and before capturing. The fixed pause is deliberately simple, not a universal wait strategy: it may waste time on a fast page or be too short for a slow request. Prefer a Selenium explicit wait for a known element, loading indicator, or other page condition. If the page continues loading at the limit, decide whether to increase the bound or capture the content available at that point.

4. Know what the screenshot contains

There are two different goals:

Goal What to do Important limit
Viewport at the bottom Scroll, wait for content to settle, then call getScreenshotAs. The output is the screenshot returned by the active browser and driver at that scroll position.
One image of the whole document Use a browser and driver method that explicitly supports full-page capture, and verify its behavior for your versions. The standard screenshot API documentation does not promise identical full-document stitching across all browser and driver combinations.

Scrolling and then taking a screenshot is appropriate when you need the visible viewport at the end of the page. If you need a stitched long-page image, confirm full-page support for your exact browser, driver, and Selenium release or use a capture service with an explicit full-page option.

5. Handle frames, nested scroll areas, and dynamic pages

Content inside an iframe

JavaScript runs in the selected frame or window. If the target content is inside an iframe, switch into it before inspecting or scrolling its document:

WebElement frame = driver.findElement(By.cssSelector("iframe.content"));
driver.switchTo().frame(frame);
((JavascriptExecutor) driver).executeScript(
    "window.scrollTo(0, document.documentElement.scrollHeight)"
);
// Take a screenshot in the selected browsing context as required.
driver.switchTo().defaultContent();

Import org.openqa.selenium.WebElement and org.openqa.selenium.By. If you need the top-level page screenshot, return to the default content before capturing. Cross-origin restrictions and frame behavior can affect what page script can inspect; Selenium’s frame switch selects the browsing context for script execution.

Scrollable panel rather than the document

If the page uses an element with its own scrollbar, scroll that element instead of the window. Locate it with a CSS selector and set its scrollTop to its scrollHeight. The screenshot will still reflect the browser’s current viewport unless your capture method supports element screenshots.

WebElement panel = driver.findElement(By.cssSelector(".results-panel"));
((JavascriptExecutor) driver).executeScript(
    "arguments[0].scrollTop = arguments[0].scrollHeight", panel
);

Fixed headers and overlays

Sticky headers remain in the viewport when you reach the bottom and can cover content. A cookie banner, chat widget, or modal can also obscure the shot. For your own application, close or hide these elements in a controlled test setup. For third-party pages, do not assume a scroll will dismiss them; use a capture method that handles the overlays when clean output is required.

6. Common errors and fixes

Symptom Likely cause Fix
ClassCastException when casting the driver The active driver implementation does not expose TakesScreenshot. Use a supported browser driver and verify the capabilities of the Selenium and driver versions in use.
Screenshot is at the top or content is missing The scroll script ran in the wrong frame, the page changed after scrolling, or the screenshot was taken before content settled. Check the selected frame, wait for a page condition, and re-check the scroll position and document height before capture.
Only the viewport is present The driver returned a viewport screenshot; scrolling alone did not create a stitched image. Use a browser-supported full-page capture path and verify it for your browser and driver combination.
Lazy images are blank The page has not loaded those images yet, or loading depends on scrolling through intermediate areas. Scroll incrementally, wait for image or page-specific readiness, then capture. A short fixed sleep cannot guarantee completion.
StaleElementReferenceException for a panel or frame The page replaced that element during a dynamic update. Locate the element again after the update and retry within a bounded wait.
Output file is empty or missing Saving failed, the destination directory does not exist, or the temporary screenshot file was moved or deleted before copying. Create the destination directory, check the exception, and copy the screenshot immediately after the call.
Browser process remains running An exception bypassed browser shutdown. Keep capture and file handling inside try and call driver.quit() in finally.
Script cannot read expected page content The script is executing in a different frame or window than the one containing the page. Select the correct window and frame before executing JavaScript; restore the default content when done.

7. Performance, reliability, and cost

  • Bound the work: set a maximum number of scroll rounds or an overall timeout. Infinite scrolling can otherwise keep automation busy indefinitely.
  • Wait for conditions: a fixed delay adds latency on fast pages and can still be too short on slow ones. Prefer a known loading signal or content condition.
  • Keep browser sessions short: use driver.quit() in a finally block, including when a screenshot or file operation fails.
  • Control the environment: browser version, driver version, viewport size, page state, and network timing can change the result. Pin and record versions for repeatable automation, and validate full-page behavior on the actual target setup.
  • Account for browser costs: a DIY Selenium flow requires a browser process, driver management, page-load time, and storage for output. Its compute and maintenance cost depends on where and how often it runs; there is no single reliable cost figure for all deployments.

Or skip the browser setup

ScreenshotNeo is a screenshot API and MCP server for developers. Its API can capture a page in one request; use full_page=true when you want the full document. See the API documentation for options and authentication.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://example.com \
  -d full_page=true \
  -o page.png

Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Each response includes page-verdict and billing headers.

For a clean shot without managing Selenium or a browser, sign up free for 1,000 screenshots a month, with no card required.

FAQ

Does scrolling to the bottom make Selenium capture the whole page?

No. It moves the page; the screenshot’s coverage depends on the browser and driver. Use a verified full-page capture method if you need one stitched document image.

Can I save the result as JPEG instead of PNG?

TakesScreenshot returns the screenshot format provided by the driver. If your workflow requires a specific image format, check the driver output and convert it with an image library.

Why does the page height keep changing?

Infinite feeds, delayed images, and content loaded by scrolling can all extend the document. Use a maximum scroll count or deadline and define what “finished” means for your use case.

Can I capture a page that requires authentication?

Yes, when your Selenium session can access it. Establish the required login or session state before scrolling, and avoid placing credentials in code that is committed or shared.