Website Screenshots with Selenium in Python

Complete guide to taking screenshots with Selenium in Python. Learn save_screenshot(), element screenshots, full page workarounds, and headless mode setup.

Blog post 5 min read

Written by

Dmytro Krasun

Published on

Selenium is one of the oldest browser automation tools, and it’s still widely used. If you already have Selenium in your stack, you can take screenshots without adding another dependency. Let me quickly show you how.

If you don’t want to read and just save time,I created a dedicated repository with tested and working examples of how to take screenshots with Selenium in Python.

However, if you don’t use Selenium and building from scratch, I recommend using Playwright instead, it is a modern and actively developed library for browser automation. Especially if that’s the only functionality you need. Or check out our guide to how to take website screenshots Python.

Quick Start

Install Selenium and webdriver-manager:

Terminal window
pip install selenium webdriver-manager

Using webdriver-manager eliminates the need to manually download ChromeDriver:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
# automatically download and use the correct ChromeDriver
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
driver.get('https://example.com')
driver.save_screenshot('screenshot.png')
driver.quit()

If you are familiar with example.com, you should not be surprised by the result:

A screenshot of the example.com website

Screenshot Methods

Selenium provides three ways to capture screenshots:

1. Save to File

driver.save_screenshot('screenshot.png')

2. Get as Bytes (PNG)

png_bytes = driver.get_screenshot_as_png()
# Save manually
with open('screenshot.png', 'wb') as f:
f.write(png_bytes)

3. Get as Base64 String

base64_string = driver.get_screenshot_as_base64()
# Useful for embedding in HTML or sending via API
import base64
png_bytes = base64.b64decode(base64_string)

Waiting for Page Load

Taking a screenshot too early means incomplete content:

Explicit Wait for Elements

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver.get('https://example.com')
# Wait for specific element to be visible
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.main-content')))
driver.save_screenshot('screenshot.png')

Fixed Timeout

import time
driver.get('https://example.com')
time.sleep(3) # Wait 3 seconds
driver.save_screenshot('screenshot.png')

Combine Both

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
driver.get('https://example.com')
# Wait for main content
try:
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.TAG_NAME, 'body')))
except:
pass
# Extra buffer for JavaScript
time.sleep(1)
driver.save_screenshot('screenshot.png')

Element Screenshots

Capture a specific element instead of the full viewport:

from selenium.webdriver.common.by import By
driver.get('https://example.com')
# Find element and screenshot it
element = driver.find_element(By.CSS_SELECTOR, '.hero-section')
element.screenshot('hero.png')

Viewport Settings

Control the browser window size:

# Set window size before navigating
driver.set_window_size(1920, 1080)
driver.get('https://example.com')
driver.save_screenshot('screenshot.png')

Or maximize:

driver.maximize_window()

Full Page Screenshots

This is where Selenium falls short. Unlike Playwright, Selenium doesn’t have native full-page support. Here’s the workaround:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from PIL import Image
import io
import time
def full_page_screenshot(driver, output_path, scroll_wait):
metrics = driver.execute_script(
"""
const body = document.body;
const html = document.documentElement;
const totalHeight = Math.max(
body.scrollHeight, body.offsetHeight, body.clientHeight,
html.scrollHeight, html.offsetHeight, html.clientHeight
);
const viewportHeight = window.innerHeight;
return { totalHeight, viewportHeight };
"""
)
total_height = int(metrics["totalHeight"])
viewport_height = int(metrics["viewportHeight"])
if viewport_height <= 0:
raise RuntimeError("Viewport height is zero")
last_scroll = max(total_height - viewport_height, 0)
positions = list(range(0, total_height, viewport_height))
if not positions or positions[-1] != last_scroll:
positions.append(last_scroll)
screenshots = []
for offset in positions:
driver.execute_script(
"document.documentElement.scrollTo(0, arguments[0]);"
"document.body.scrollTo(0, arguments[0]);",
offset,
)
time.sleep(scroll_wait)
png = driver.get_screenshot_as_png()
screenshots.append(Image.open(io.BytesIO(png)))
if not screenshots:
raise RuntimeError("No screenshots captured")
scale = screenshots[0].height / viewport_height
total_height_px = int(total_height * scale)
total_width_px = screenshots[0].width
stitched = Image.new("RGB", (total_width_px, total_height_px))
y = 0
for img in screenshots:
remaining = total_height_px - y
if remaining <= 0:
break
if img.height > remaining:
img = img.crop((0, 0, img.width, remaining))
stitched.paste(img, (0, y))
y += img.height
stitched.save(output_path)
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.set_window_size(1920, 1080)
driver.get('https://screenshotone.com')
full_page_screenshot(driver, 'fullpage.png', 0.2)
driver.quit()

It did screenshot the full page, but it had some issue. E.g. it screenshots scrollbar, you can try to fix that by executing the following JavaScript code:

document.body.style.overflow = "hidden";

Another issue was that the top navigation bar appeared in the screenshot a few times:

A screenshot of the screenshotone.com website with the top navigation bar appearing in the screenshot a few times

There are many ways to fix that:

  1. Try to fixate all the elements.
  2. Do not stitch pages together, but take a screenshot of the whole page by applying different techniques. However that will also have its own issues.

But unfortunately, it is out of the scope of this guide. Check out our Playwright (Python) guide to how to take full page screenshots for some examples on that can be solved.

If full-page screenshots is a critical part of your workflow, consider using our API instead.

Headless Mode

For server environments:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
options.add_argument('--window-size=1920,1080')
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
driver.save_screenshot('screenshot.png')
driver.quit()

Chrome Options for Screenshots

Useful options for screenshot automation:

options = Options()
options.add_argument('--headless')
options.add_argument('--window-size=1920,1080')
options.add_argument('--hide-scrollbars')
options.add_argument('--force-device-scale-factor=2') # Retina
options.add_argument('--lang=en-US')
options.add_argument('--disable-extensions')

Error Handling

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, WebDriverException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
def safe_screenshot(url, output_path):
driver = None
try:
driver = webdriver.Chrome()
driver.set_window_size(1920, 1080)
driver.get(url)
# Wait for page
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.TAG_NAME, 'body')))
driver.save_screenshot(output_path)
return True
except TimeoutException:
print(f"Timeout loading {url}")
return False
except WebDriverException as e:
print(f"WebDriver error: {e}")
return False
finally:
if driver:
driver.quit()

Multiple Screenshots

Process multiple URLs:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
urls = [
'https://example.com',
'https://github.com',
]
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.set_window_size(1920, 1080)
for i, url in enumerate(urls):
try:
driver.get(url)
driver.implicitly_wait(5)
driver.save_screenshot(f'screenshot_{i}.png')
print(f'Success: {url}')
except Exception as e:
print(f'Failed: {url} - {e}')
driver.quit()

Check our guide how to take bulk screenshots with Selenium in Python for more details.

Playwright vs Selenium for Screenshots

FeatureSeleniumPlaywright
Native full pageNoYes
Async supportNoYes
Element screenshotsYesYes
Wait mechanismsExplicit onlyMultiple options
Setup complexityHigherLower
SpeedSlowerFaster

My recommendation: If you’re starting fresh, use Playwright. If you already have Selenium in your project, it works fine for basic screenshots.

When to Use a Screenshot API

Selenium is fine for small volumes, but at scale:

  • Browser process management becomes complex.
  • Memory leaks are common.
  • No native full-page support.

The best use case for that is when you perform testing of your websites: your run and screenshot pages and then close the browser and forget about resources. In that case, resource management is less of an issue.

For production workloads, consider a screenshot API like ScreenshotOne. See the main Python screenshot guide for all options.

Summary

Selenium screenshot basics:

  1. Use save_screenshot() for simple saves
  2. Use webdriver-manager to avoid driver management.
  3. Always wait for content before capturing.
  4. Full page requires workarounds (body element or scroll+stitch).
  5. Use headless mode for servers.

Frequently Asked Questions

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at support@screenshotone.com.

How to take screenshot in Selenium Python?

Use driver.save_screenshot('screenshot.png') to save directly to file, or driver.get_screenshot_as_png() to get the screenshot as bytes for further processing.

How to take full page screenshot in Selenium Python?

Selenium doesn't have native full page support. You need to scroll through the page, capture sections, and stitch them together. Or use the body element screenshot method in headless mode.

What is the difference between save_screenshot and get_screenshot_as_png?

save_screenshot() saves directly to a file, while get_screenshot_as_png() returns the image as bytes. Use get_screenshot_as_png() when you need to process the image in memory.

Read more Screenshot rendering

Interviews, tips, guides, industry best practices, and news.

View all posts
How to screenshot websites in Next.js

How to screenshot websites in Next.js

There 3 simple ways to render website screenshots in Next.js—using Puppeteer, Cloudflare Browser Rendering, and a screenshot API like ScreenshotOne or similar.

Read more

Automate website screenshots

Exhaustive documentation, ready SDKs, no-code tools, and other automation to help you render website screenshots and outsource all the boring work related to that to us.