ScreenshotRender
← Back to blog
Tutorials

Selenium Screenshot: 3 Ways to Capture a Web Page

Robert Belt·9 min read
Updated On :
Orange minimalist illustration of Selenium turning a web page into a screenshot

Every Selenium tutorial shows you one method call and calls it done. None of them mention that in Chrome it captures only the visible viewport, which is why your full page screenshot keeps coming back cropped at the fold. By the end of this you'll know how to capture the page, a single element, and a true full page shot in both Chrome and Firefox, plus when one HTTP call beats the whole setup.

Selenium is a browser automation framework, not a screenshot tool, so its capture API is small and a few of its sharpest edges are undocumented in the tutorials that rank for this. We'll go from the basic save, to a single element, to the full page, and finish with the cases where driving a local browser is the wrong tool for the job.

How do you take a screenshot in Selenium?

You take a screenshot in Selenium with a single method on the driver: driver.save_screenshot("page.png") in Python, or ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE) in Java. Point the driver at a URL first, then call the method, and you get a PNG of the current viewport written to disk.

That one line is the whole answer for the common case, and the rest of this post is the cases it does not cover: a single element, the full scrollable page, and the bot-protected sites where a vanilla driver gets a challenge page instead of the content. The capture itself is rarely the hard part. Getting the page to render cleanly before you shoot it is.

If you only need a clean image of a public URL and you do not want a browser running on your machine at all, that is the one job a screenshot API does better than Selenium. With ScreenshotRender the whole capture is one line: https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://news.ycombinator.com&fullPage=true. No driver, no WebDriver binary, no Chrome to patch. The rest of this guide stays in Selenium, and we'll come back to where the API wins near the end.

How do you save a Selenium screenshot in Python and Java?

You save a Selenium screenshot by calling a save or get method on the driver after the page loads, choosing a file, raw bytes, or base64 depending on what you do next. The Selenium Python bindings give you three variants of the same capture.

In Python, driver.save_screenshot("page.png") and driver.get_screenshot_as_file("page.png") both write a PNG to disk and return a boolean. When you need the image in memory instead, driver.get_screenshot_as_png() hands back raw bytes and driver.get_screenshot_as_base64() hands back a base64 string you can drop straight into a data URL or a JSON payload.

Java routes everything through the TakesScreenshot interface. Cast the driver, pick an output type, and copy the result: File shot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE) then FileHandler.copy(shot, new File("page.png")). Swap OutputType.FILE for OutputType.BASE64 or OutputType.BYTES to get the same three shapes Python exposes.

One catch decides whether any of these come back usable: timing. Call the screenshot the instant after get() returns and you can capture a half-rendered page or a blank frame. Wait for a real signal first, an element that proves the content has painted, with an explicit WebDriverWait rather than a fixed sleep. That single habit removes most blank-screenshot bug reports.

How do you screenshot a single element in Selenium?

You screenshot a single element in Selenium by finding it first, then calling the screenshot method on the element instead of the driver. Selenium 4 added this, and it crops the image to the element's bounding box for you, so you no longer shoot the whole page and clip it afterward.

In Python you find the node and capture it in two lines: el = driver.find_element(By.CSS_SELECTOR, ".price-card") then el.screenshot("element.png"). The element also exposes screenshot_as_png and screenshot_as_base64 if you want bytes or a string. In Java it mirrors the driver call: File shot = el.getScreenshotAs(OutputType.FILE), because a Selenium 4 WebElement implements the same TakesScreenshot interface the driver does.

Element shots are the right tool for a chart, a pricing table, or a single card you want to embed somewhere. The catch is that the element has to be in the layout and scrolled into view; a node that is hidden or outside the rendered area gives you an empty or clipped image, which loops back to the same timing rule from the last section.

Why can't Selenium take a full page screenshot in Chrome?

Selenium can't take a full page screenshot in Chrome because the standardized capture command grabs only the viewport, and Chrome never added an extension to go beyond it. The W3C WebDriver Take Screenshot command is defined against the top-level browsing context's viewport, so by spec you get what is currently on screen and nothing below the fold.

This is the gotcha the one-liner tutorials skip. You call driver.save_screenshot("page.png") on a long article, open the file, and the bottom three quarters of the page are simply not there. Nothing errored. The driver did exactly what the standard says, which is capture the viewport, and the viewport was the first screenful of a much longer page.

Firefox is the exception. Mozilla's geckodriver implemented a non-standard full page command, which is why the Firefox driver has a full page method and Chrome does not. For Chrome you drop one level down to the DevTools Protocol, which is the next section.

How do you take a full page screenshot in Selenium?

You take a full page screenshot in Selenium one of two ways depending on the browser: Firefox has a native method, and Chrome needs a DevTools Protocol call. Both stitch the entire scrollable document instead of the visible slice.

In Firefox it is a single dedicated call: driver.get_full_page_screenshot_as_file("full.png"), with get_full_page_screenshot_as_png and get_full_page_screenshot_as_base64 alongside it. These exist only on the Firefox driver, so the same code against Chrome raises an attribute error.

In Chrome you call the Page.captureScreenshot DevTools method directly: driver.execute_cdp_cmd("Page.captureScreenshot", {"captureBeyondViewport": True, "fromSurface": True}). The captureBeyondViewport flag is the whole trick; it tells Chrome to render past the fold. The call returns a dict with a base64 image in its data field, which you decode and write to disk. Java reaches the same protocol through executeCdpCommand on the ChromeDriver, and many Java teams instead pull in a stitching library like aShot, which scrolls and pastes the slices together.

Either path works, but notice what just happened: a full page screenshot in Selenium is no longer one portable line. It is browser-specific code, a protocol call, and base64 decoding, and you maintain a different branch for Chrome and Firefox. The scroll-and-stitch mechanics underneath are worth understanding, and we broke them down in our guide to screenshotting an entire webpage.

One call. Full page. Both browsers' worth of edge cases handled.

Skip the per-browser branches, the DevTools Protocol, the base64 decoding, and the bot fights. ScreenshotRender renders the page on its own infrastructure and returns a clean image, with cookie banners and ads already stripped. Add fullPage=true and you get the whole scrollable document. 100 free screenshots, no credit card.

Try a render

When should you use a screenshot API instead of Selenium?

You should use a screenshot API instead of Selenium when the screenshot is the product, not a step inside a test, and the failures below start eating your time. Selenium is built to drive a browser through a flow; when all you want is a clean image of a URL, most of what Selenium asks you to own is overhead.

  • Bot protection. A vanilla Selenium browser gets served a challenge page on bot-protected sites, so your capture is the challenge, not the content. ScreenshotRender ships Stealth Mode on the Hobby plan and above; our guide to screenshotting Cloudflare-protected sites covers what actually changes.
  • Server and CI memory. Each Chrome or Firefox instance is memory-hungry, and a small container or a CI runner will kill the process when several captures run at once. Moving the render off your host removes the whole class of problem, since nothing heavy runs on your machine.
  • Full page fragility. As the last section showed, full page in Selenium is browser-specific glue you maintain. An API takes fullPage=true and returns the whole document the same way on every site.
  • UI clutter. Cookie consent banners, ad overlays, and chat widgets land in your Selenium shots and you write dismissal code for each one. ScreenshotRender removes them automatically before every capture, on every plan including the free one, so the image is the page rather than the page plus three popups.

The trade-off is real and worth stating plainly: Selenium can log in, click through a flow, and screenshot a page behind a session, and a URL-only API cannot. Keep Selenium for authenticated journeys and end-to-end tests. Reach for the API when you just need the picture, and if you are weighing providers, we compared them in our guide to the best screenshot API.

The API also pays only for what works. With ScreenshotRender a failed render does not cost a credit, repeat captures of the same URL come back from an edge cache, and the response carries the page title, description, and favicon, which is handy if you are building a link preview card. Theurl and fullPage parameters cover most jobs, and a wait parameter handles pages that finish rendering after the first paint.

Common questions about Selenium screenshots

How do I take a full page screenshot in Selenium Python?

In Firefox, call driver.get_full_page_screenshot_as_file("full.png"), which geckodriver supports natively. In Chrome there is no native full page method, so call the DevTools Protocol with driver.execute_cdp_cmd("Page.captureScreenshot", {"captureBeyondViewport": True}) and decode the base64 in the data field of the result. The standard save_screenshot grabs only the visible viewport in Chrome, which is why a plain capture comes back cropped.

How do I screenshot a specific element in Selenium?

Find the element, then call its screenshot method rather than the driver's. In Python that is el.screenshot("element.png"); in Java it is el.getScreenshotAs(OutputType.FILE). Selenium 4 crops the image to the element's bounding box automatically, so you do not have to capture the whole page and clip it. The element has to be scrolled into view first, or the image comes back empty.

Why is my Selenium screenshot blank or white?

The usual cause is capturing before the page has rendered. Replace any fixed sleep with an explicit WebDriverWait that waits until a key element is present or visible, so you shoot after the content paints. In headless mode, set a real window size as well, since headless Chrome starts with a small default, and scroll lazy-loaded content into view before the shot.

Can Selenium take a screenshot in headless mode?

Yes. Start Chrome in headless mode with the --headless=new argument, or Firefox with -headless, and call the same screenshot methods you would with a visible window. Headless is the normal choice on servers and CI because there is no display attached, but set an explicit window size so the viewport is not tiny and your captures are not cramped.

How do I save a Selenium screenshot as base64?

Use the base64 variant instead of writing a file. In Python call driver.get_screenshot_as_base64(); in Java call getScreenshotAs(OutputType.BASE64). You get back a string you can embed in an image data URL or send inside a JSON request without ever touching the filesystem, which is the convenient shape when the screenshot is going straight into another service.

The honest takeaway: Selenium captures screenshots well when capturing is one step inside automation you already run. Use save_screenshot for the viewport, the element method for one node, and the Firefox native call or Chrome's DevTools Protocol for the full page. And when the screenshot itself is the goal and you would rather not run, patch, and scale a browser to get it, one HTTP call hands you a clean image with none of the upkeep.

Keep reading