How to Capture a Website Screenshot with Python Selenium on macOS
Capture a website screenshot on macOS with Python Selenium. Set up WebDriver, save window or element images, handle full-page limits, and troubleshoot common errors.
To capture a website screenshot with Python Selenium on macOS, install Selenium, open a browser with WebDriver, navigate to the page, and call driver.save_screenshot("screenshot.png"). This saves a PNG of the current browser window. Use element.screenshot(...) for one element; full-page capture depends on the browser.
1. Install Selenium on macOS
Use a virtual environment so the Selenium package is installed into the same Python environment that runs your script. Selenium’s current Python bindings documentation supports Python 3.10 and later. Modern Selenium uses Selenium Manager to resolve browser drivers in most supported setups, so a separate driver download is usually unnecessary. You still need the browser you intend to automate installed on the Mac.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U selenium
Check that the virtual environment is active before running your script. If you use a different browser, choose its matching WebDriver constructor and ensure that browser is installed. Selenium documents Chrome, Edge, Firefox, Safari, and other browser implementations; setup details can vary by browser.
2. Capture the current browser window
This runnable example uses Chrome, writes the image to the current working directory, checks Selenium’s success value, and always closes the browser session.
from pathlib import Path
from selenium import webdriver
url = "https://example.com"
output = Path("screenshot.png")
driver = webdriver.Chrome()
try:
driver.get(url)
saved = driver.save_screenshot(str(output))
if not saved:
raise OSError(f"Could not save screenshot to {output.resolve()}")
finally:
driver.quit()
print(f"Saved {output.resolve()}")
save_screenshot writes a PNG of the current window and returns a boolean. The relative path is resolved from the process’s working directory, which may not be the directory containing the script. Use an absolute path or print Path(...).resolve() when locating the output is important.
Wait for a page condition when needed
driver.get() navigates to the URL, but pages can continue changing after navigation, especially when content loads dynamically. If the screenshot must include a particular element, wait for it explicitly rather than relying on a fixed pause.
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
output = Path("ready.png")
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
WebDriverWait(driver, 20).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "main"))
)
if not driver.save_screenshot(str(output)):
raise OSError(f"Could not save {output.resolve()}")
finally:
driver.quit()
Replace main with a selector that indicates the content you need is ready. A visible element is not proof that every image or asynchronous widget has finished loading; choose a page-specific readiness condition if those details matter.
3. Choose what to capture
| Need | Selenium method | What to know |
|---|---|---|
| Visible browser window | driver.save_screenshot(path) |
Captures the current window as PNG; it does not promise content below the fold. |
| One element | element.screenshot(path) |
Find the element first; useful for a component or image within the page. |
| PNG in memory | driver.get_screenshot_as_png() |
Returns PNG bytes for further processing or storage. |
| Base64 data | driver.get_screenshot_as_base64() |
Returns an encoded screenshot string. |
| Full document | Browser-specific API | Firefox’s Python API documents save_full_page_screenshot(path); do not assume identical support across browsers. |
Capture one element
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
output = Path("element.png")
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
element = driver.find_element(By.CSS_SELECTOR, "main")
if not element.screenshot(str(output)):
raise OSError(f"Could not save {output.resolve()}")
finally:
driver.quit()
The selector must match an element on the page. If the element is not present at navigation time, wait for it with WebDriverWait before taking its screenshot.
Get screenshot bytes or base64
from pathlib import Path
from selenium import webdriver
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
png_bytes = driver.get_screenshot_as_png()
Path("screenshot.png").write_bytes(png_bytes)
png_base64 = driver.get_screenshot_as_base64()
print(f"Base64 characters: {len(png_base64)}")
finally:
driver.quit()
Use PNG bytes when a Python library or upload client accepts binary data. Base64 is useful when an interface specifically expects encoded image data, but it takes more space than the original binary representation.
Full-page screenshots
A normal window screenshot is not a full-document screenshot. The reviewed Selenium documentation specifically lists save_full_page_screenshot(path) in the Firefox Python API. Since full-page support and behavior vary by browser, check the current API for your chosen browser and validate the resulting dimensions and page content. Avoid assuming that a window resize or a series of viewport captures will produce a seamless full-page image: sticky headers, lazy-loaded content, and dynamic layouts can make stitched captures differ.
4. Practical choices and edge cases
- Output path: Relative paths use the process working directory. Resolve the path to confirm where the file will be written.
- PNG output: Selenium’s documented screenshot methods produce PNG data or files. If another image format is required, convert the saved image with an image-processing library.
- Page readiness: Wait for the particular content needed. A page load event may not mean every dynamic section is ready.
- Window versus document: Decide whether you need the visible window, a single element, or the whole document before selecting a method.
- Session cleanup: Call
driver.quit()in afinallyblock so browser resources are released even when navigation or file writing raises an exception. - Browser selection: Use a browser installed on the Mac and a Selenium driver constructor for that browser. Browser-specific features, especially full-page capture, need browser-specific verification.
5. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| WebDriver cannot start or reports a driver error | Outdated Selenium, missing browser, or a browser/driver setup issue. | Upgrade Selenium in the active environment with python -m pip install -U selenium, confirm the browser is installed, and retry with Selenium Manager. Use manual driver configuration only if your setup requires it. |
| Screenshot is not where expected | The relative output path is based on the process working directory. | Print Path("screenshot.png").resolve() or supply an absolute path. Check the boolean returned by save_screenshot. |
| Image shows only the top viewport | save_screenshot captures the current window, not necessarily the whole document. |
Use a documented full-page method for the browser in use, such as Firefox’s API method, or capture a specific element. |
| Expected content is missing | Dynamic page content may not have appeared before capture. | Wait for a relevant element or another page-specific readiness signal before saving. |
| Browser process is left open after an exception | Cleanup did not run after a failed navigation or save. | Put driver.quit() in finally, as in the examples. |
| Screenshot file is empty or saving fails | Output location or I/O permissions may prevent writing. | Use a writable absolute path, check the method’s boolean return, and raise or log an error when it is false. |
6. Performance, reliability, and cost
Each local capture starts a browser session, navigates to a page, waits for the content you require, and writes an image. Reusing a browser session for multiple pages can avoid repeated startup overhead, but isolate pages carefully and always quit the session at the end. Longer waits improve the chance of capturing slow content but increase run time; use a specific readiness condition and a bounded timeout instead of an arbitrary long sleep.
For repeatable captures, keep the browser choice, viewport, URL, readiness condition, and output path consistent. A live page can change between runs, so Selenium does not make the page itself deterministic. Local Selenium has no per-screenshot ScreenshotNeo charge, but you manage the machine, browser processes, execution time, and any infrastructure used to run the script.
7. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its API returns a PNG, JPEG, WebP, or PDF from one GET request, and the API documentation describes its options.
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo’s free 1,000 screenshots a month, with no card.
FAQ
Does Selenium save screenshots as PNG on macOS?
Yes. The documented WebDriver screenshot method saves the current window as PNG; macOS does not change that method’s output format.
Do I need to download ChromeDriver separately?
Usually not with a modern Selenium setup, because Selenium Manager handles driver installation in most supported configurations. The browser itself must still be installed.
Can I take a screenshot without saving a file?
Yes. Retrieve PNG bytes with get_screenshot_as_png() or a base64 string with get_screenshot_as_base64(), then pass the result to your application.
Will the screenshot include cookie banners or popups?
A local Selenium capture reflects what the browser displays unless your script handles those elements. ScreenshotNeo can accept and remove supported consent banners, popups, and chat widgets before capture.


