sodcalculator

10 Tech How-To

Fix Selenium Headless Chrome Screenshots on Ubuntu

Guide 10-18354 · Updated · Step by step

If you’re running Selenium with headless Chrome on an Ubuntu server and screenshots come back blank, black, or fail entirely, this guide walks through the most common causes and their fixes. You’ll learn how to configure Chrome, Selenium, and the server environment so screenshots capture correctly every time.

What You’ll Need

  • Ubuntu server (20.04 or later) with sudo access
  • Python 3 and pip (or your preferred Selenium language binding)
  • Selenium installed (e.g., pip install selenium)
  • Chrome or Chromium installed (see Step 1)
  • Basic familiarity with the command line

Step-by-Step

  1. Install Chrome/Chromium and the matching driver.
    On Ubuntu, you can install Chromium via sudo apt install chromium-browser (or chromium on newer releases). For Chrome, download the .deb from Google’s site. Then install the matching ChromeDriver from the same version. Use chromedriver --version to verify. Mismatched versions are a top cause of failures.
  2. Install required system libraries.
    Chrome on a headless server needs certain libraries. Run:
    sudo apt update && sudo apt install -y libx11-xcb1 libxcomposite1 libxdamage1 libxrandr2 libgbm1 libasound2 libnss3 libatk-bridge2.0-0
    Missing libs often cause Chrome to crash silently or produce blank screenshots.
  3. Set Chrome options for headless mode.
    In your Selenium script, add these options:

    options = webdriver.ChromeOptions()
    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')

    --no-sandbox is often required when running as root or in a container. --disable-dev-shm-usage prevents crashes in low-memory environments. --window-size ensures the viewport is large enough for the content you want to capture.

  4. Wait for the page to load fully.
    Selenium’s get() waits for the initial page load, but dynamic content (AJAX, images, fonts) may still be loading. Use explicit waits:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, 'body')))

    Or simply time.sleep(2) if you need a quick fix.

  5. Take the screenshot with the correct method.
    Use driver.save_screenshot('screenshot.png') or driver.get_screenshot_as_file('path.png'). For full-page screenshots, you may need a library like selenium-screenshot or use driver.set_window_size() to match the page height first.
  6. Check file permissions.
    Ensure the directory where you save screenshots is writable by the user running the script. For example, chmod 755 /path/to/screenshots or run the script as a user with write access.
  7. Test with a minimal script.
    Create a simple script that loads a known page (e.g., https://example.com) and takes a screenshot. If that works, your issue is likely page-specific. If not, the problem is in the environment.

Common Mistakes

  • Using the wrong ChromeDriver version. Always match the driver to your Chrome version exactly.
  • Forgetting --no-sandbox when running as root. This causes immediate crashes.
  • Not setting a window size. The default is 800×600, which may clip the page.
  • Taking the screenshot before the page finishes loading. Use waits.
  • Ignoring the --disable-dev-shm-usage flag. In Docker or low-memory servers, /dev/shm is small, causing Chrome to crash.

Tips

  • Use --hide-scrollbars to avoid scrollbars appearing in your screenshot.
  • Set a custom user agent if the site blocks headless browsers: options.add_argument('user-agent=Mozilla/5.0 ...').
  • For full-page screenshots, consider using a library like selenium-wire or manually resizing the window to the page height.
  • Run your script in a virtual environment to avoid dependency conflicts.
  • Log the Chrome stderr output to debug crashes: options.add_argument('--enable-logging=stderr').

Troubleshooting

Screenshot is black or blank. This often means the page didn’t render. Try adding --disable-gpu and --no-sandbox, and increase the wait time. Also check if the page uses WebGL or canvas – those may need --enable-webgl.

Chrome crashes immediately. Run chromedriver manually to see the error. Missing libraries are common – install them as in Step 2. Also check if you’re using a 32-bit vs 64-bit mismatch.

Timeout waiting for page load. Some sites never finish loading. Set a page load timeout: driver.set_page_load_timeout(30) and catch the exception, then take the screenshot anyway.

Permission denied when saving. Check the directory permissions and that the path is absolute.

Works locally but not on the server. Compare Chrome versions and options. The server may have a different architecture or missing fonts – install fonts-liberation and fonts-noto.

Frequently Asked Questions

Why do I need --no-sandbox?

Chrome’s sandbox requires certain kernel features that are often disabled in containers or when running as root. Disabling it is safe for a single-purpose server.

Can I use Firefox instead?

Yes, but the steps differ. Firefox uses geckodriver and has similar headless options. The same principles apply: install the driver, set headless mode, and wait for load.

How do I take a full-page screenshot?

Set the window size to the page’s full height using driver.set_window_size(width, height) after getting the page, or use a library like selenium-screenshot that handles it automatically.

What if the screenshot is missing images?

Images may load lazily. Scroll through the page or wait for network idle. You can also use driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') to trigger loading.

Is there a way to take a screenshot without opening a window?

Headless mode does exactly that – it runs without a visible window. The --headless flag is all you need.

Why does it work with Chrome but not Chromium?

Chromium may lack proprietary codecs or fonts. Install the same dependencies and use the same options. Sometimes the issue is just a version mismatch.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →