ScreenshotNeo

BlogHow-to

How to Fix Full-Page Screenshots in Selenium Firefox

Use Firefox’s full-document screenshot API, then check viewport size, driver versions, packaging, preferences and horizontal overflow.

By the ScreenshotNeo team1 October 20268 min read

Use Firefox’s full-document screenshot method instead of the ordinary viewport screenshot call. In Selenium Python, call driver.get_full_page_screenshot_as_file() (or one of Firefox’s other full-page methods), set the window size first, and save to a path ending in .png.

from selenium import webdriver

driver = webdriver.Firefox()
try:
    driver.set_window_size(1440, 900)
    driver.get("https://example.com")
    driver.get_full_page_screenshot_as_file("full-page.png")
finally:
    driver.quit()

driver.save_screenshot("page.png") captures the current window. If that file contains only the visible viewport, that is expected; switch to the Firefox full-page API. Selenium documents the operation as a full document screenshot of the current window in its Firefox WebDriver API.

1. A reliable minimal implementation

Use an absolute output path while diagnosing failures and always close the driver in a finally block.

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

output = Path("/absolute/path/full-page.png")
options = Options()
# options.add_argument("--headless")  # enable in CI when needed

driver = webdriver.Firefox(options=options)
try:
    driver.set_window_size(1440, 900)
    driver.get("https://example.com")
    driver.get_full_page_screenshot_as_file(str(output))
    print(f"saved {output}")
finally:
    driver.quit()

Firefox exposes several equivalent full-document calls: get_full_page_screenshot_as_file, save_full_page_screenshot, get_full_page_screenshot_as_png, and a base64 variant. Use the file method for a normal PNG, the binary method when you need to process bytes in memory, and the base64 method when an API requires encoded data.

2. Wait for the page before capturing

A full-page endpoint does not guarantee that your application’s asynchronous content has finished rendering. Wait for the condition your page owns: a loading marker disappearing, a results element appearing, fonts loading, or images completing.

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

wait = WebDriverWait(driver, 30)
driver.get("https://example.com/report")
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
wait.until(lambda d: d.find_element(By.CSS_SELECTOR, "main.report").is_displayed())
driver.get_full_page_screenshot_as_file("/absolute/path/report.png")

For lazy-loaded sections, scroll through the document before the final capture, then wait briefly for image decoding. This is page-specific behavior, so verify the result on the target application.

driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
driver.execute_script("window.scrollTo(0, 0)")
wait.until(lambda d: d.execute_script("return Array.from(document.images).every(i => i.complete)"))
driver.get_full_page_screenshot_as_file("/absolute/path/report.png")

3. Deterministic viewport and output checks

Set the viewport before navigation or capture so screenshots have predictable width and responsive layout. Selenium documents set_window_size(width, height) and related window APIs.

driver.set_window_size(1440, 900)
driver.get("https://example.com")
width, height = driver.execute_script("return [document.documentElement.scrollWidth, document.documentElement.scrollHeight]")
print({"document_width": width, "document_height": height})
driver.get_full_page_screenshot_as_file("/absolute/path/full-page.png")

After capture, inspect the PNG dimensions. A viewport-sized image usually means the ordinary screenshot method was called, a viewport-only preference is active, or a known layout edge case prevented the full-document endpoint from working.

4. Version and installation compatibility

Treat Firefox, geckodriver and Selenium as one compatibility set. Mozilla’s geckodriver support table lists geckodriver 0.37.1 with Selenium at least 3.11 and Firefox 115 ESR; newer Firefox releases generally have better support. Check the current geckodriver support documentation when upgrading.

firefox --version
geckodriver --version
python -c "import selenium; print(selenium.__version__)"

Upgrade or pin the three components together in CI, then rerun the minimal diagnostic script. A driver that starts successfully can still lack support for a screenshot endpoint or expose different behavior across versions.

5. Containerized Firefox and Snap packaging

Snap and other containerized Firefox installations can expose a different filesystem to Firefox and geckodriver. The executable, profile directory and output path must be visible to both processes. Use the matching geckodriver path inside the package environment and choose a profile directory that both sides can access. Mozilla describes this packaging caveat in its geckodriver documentation.

Symptoms include a session that starts but cannot write the PNG, a missing profile, or a screenshot that is unexpectedly blank. Confirm the paths from inside the same container or package namespace where the test runs.

6. Check the screenshot preference

Firefox’s remote.screenshot.use_readback preference controls how screenshot pixels are read. Mozilla documents that when it is true, captures read only currently composited pixels; full-document, clip and element screenshots can then degrade to the viewport. The documented default is false.

from selenium.webdriver.firefox.options import Options

options = Options()
options.set_preference("remote.screenshot.use_readback", False)
driver = webdriver.Firefox(options=options)

Set the preference before creating the driver, and remove conflicting enterprise or profile settings from the test environment.

7. Horizontal overflow: the Firefox edge case

A geckodriver issue reports that the /moz/screenshot/full endpoint can return only the viewport when a document has horizontal scrolling. Check the document width before capture:

scroll_width, client_width = driver.execute_script(
    "return [document.documentElement.scrollWidth, document.documentElement.clientWidth]"
)
print({"scroll_width": scroll_width, "client_width": client_width})

If scrollWidth is larger than the intended capture width, test a layout with horizontal overflow removed. If the page must remain horizontally scrollable, capture deterministic viewport segments and stitch them in your own pipeline, or use a different capture method after validating its treatment of fixed and sticky elements.

8. Headless CI diagnostics

Run the same script in headed and headless modes. If headed works but headless does not, record the Firefox, geckodriver and Selenium versions, window size, preference values and output path from both environments.

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.add_argument("--headless")
options.set_preference("remote.screenshot.use_readback", False)

driver = webdriver.Firefox(options=options)
try:
    driver.set_window_size(1440, 900)
    driver.get("https://example.com")
    print(driver.execute_script("return document.readyState"))
    print(driver.execute_script("return [document.documentElement.scrollWidth, document.documentElement.scrollHeight]"))
    driver.get_full_page_screenshot_as_file("/absolute/path/full-page.png")
finally:
    driver.quit()

9. Firefox DevTools control test

Firefox DevTools provides :screenshot filename.png --fullpage. Mozilla states that --fullpage includes portions outside the current window bounds, and the helper also supports --delay for pages that need time to settle. Use this as an independent control test when Selenium output is cropped.

:screenshot /absolute/path/full-page.png --fullpage --delay 2

If DevTools captures the full page but Selenium does not, focus on the WebDriver method, preference, driver version and horizontal overflow checks above.

10. Troubleshooting checklist

Symptom Likely cause Fix
Only the viewport is saved save_screenshot was used Call get_full_page_screenshot_as_file or another Firefox full-page method.
Full-page method still returns viewport remote.screenshot.use_readback=true Set it to false before creating the driver.
Image is blank Page or browser process was not ready, or a container path is inaccessible Wait for the page’s ready condition and verify executable, profile and output paths inside the container.
Lower sections are missing Lazy loading or application rendering is incomplete Wait for the application condition, scroll to trigger lazy loading, wait for images, then capture.
Capture fails after an upgrade Firefox, geckodriver and Selenium versions are mismatched Check Mozilla’s support table and pin a compatible set.
Wide page is cropped Horizontal overflow triggers a geckodriver edge case Remove unintended overflow, constrain the layout, or use segmented capture.
File cannot be found Relative path resolves in an unexpected working directory Use an absolute path ending in .png and verify permissions.

11. Fixed and sticky elements

Full-document capture implementations may render fixed or sticky elements differently as the page is laid out beyond the viewport. Validate headers, cookie notices, chat buttons and other overlays on the exact page you capture. If an element repeats down the image, hide it with page-specific CSS for the test or use a capture pipeline that handles those layers explicitly.

12. Performance, reliability and cost

  • Performance: Full-document images are taller and larger than viewport shots. Keep the viewport width intentional, avoid unnecessary device scale factors, and wait only for conditions that affect the screenshot.
  • Reliability: Pin browser dependencies, use absolute paths, disable conflicting screenshot preferences, and log document dimensions and readiness state.
  • Memory: Very long pages can require substantial browser and image memory. Split extremely long or horizontally scrolling documents when a single bitmap is not practical.
  • Reproducibility: Keep viewport size, user agent, locale, timezone, authentication state and page data stable between runs.

13. Or skip the browser setup

For an API-based capture, ScreenshotNeo returns a screenshot or PDF from one GET request. Cookie and consent banners are accepted and removed before the shot, along with more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers.

Read the ScreenshotNeo API documentation for the complete option list, including full-page capture with lazy images, selectors, device presets, retina scale, waits, custom CSS and JavaScript, request blocking, headers, cookies, user agents, timezone, geolocation, caching, signed links, async jobs, bulk capture, usage and PDF controls.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

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)

Node.js

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 fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.

14. FAQ

Why does Selenium Firefox save only what I can see?

That is the behavior of the ordinary current-window screenshot call. Use Firefox’s full-document screenshot method.

Does full-page capture require a larger window?

No, but setting a deterministic window size controls responsive layout and makes output dimensions reproducible.

Can I save JPEG or WebP with Selenium’s Firefox method?

The documented full-page file methods write PNG files. Convert the PNG afterward if another format is required.

What should I check first in CI?

Check the full-page method, absolute PNG path, window size, Firefox/geckodriver/Selenium versions, container paths and the remote.screenshot.use_readback preference.