Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Selenium 4’s ChromeOptions and add Chrome’s --headless=new argument. Pass the options object to webdriver.Chrome, wait for dynamic content when necessary, and always call driver.quit() in a finally block.

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1440,1000")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    print(driver.title)
finally:
    driver.quit()

This starts Chrome without displaying a normal browser window. The rest of this guide covers installation, driver versions, waits, viewport control, CI troubleshooting, and an API alternative when you do not need to manage a browser process yourself.

What background (headless) Chrome means

Headless Chrome runs the browser engine without opening a visible desktop window. Selenium still creates a normal WebDriver session: it can navigate, execute JavaScript, find elements, take screenshots, and interact with pages. Only the displayed window is omitted.

For current Selenium Python bindings, use the Chromium argument --headless=new. Older examples that assign options.headless = True are not the current recommended form; Selenium’s guidance says that property form was removed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Selenium and prepare Chrome

Install the Python package

Install Selenium into the same Python environment that will run your script:

python -m pip install selenium

Selenium ships with Selenium Manager, the official driver manager of the Selenium project. When a driver is not already available, the Selenium bindings can invoke Selenium Manager to discover, download, and cache a compatible driver. In supported configurations it can also manage Chrome browser downloads.

Check the environment before running

  • A Chrome or Chromium installation must be available, or Selenium Manager must be allowed to download a browser in the configuration you use.
  • The first driver or browser resolution may require outbound network access. Proxies, offline workers, and restricted CI networks can prevent it.
  • Linux containers need the browser’s required system libraries. The headless flag does not install operating-system dependencies.
  • If Chrome is installed in a nonstandard location, configure its binary path explicitly.

Keep the Selenium package, browser, and driver version policy consistent across development and deployment. Selenium Manager supports configuration through command-line options, a se-config.toml file, and environment variables, including browser-version selection.

Run a minimal headless script

The following complete program opens a page, prints its title, and closes Chrome whether navigation succeeds or raises an exception:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")

# Set this when layout or screenshots must be repeatable.
options.add_argument("--window-size=1440,1000")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    print(driver.title)
finally:
    driver.quit()

ChromeOptions.add_argument() is the Python API for adding Chrome command-line arguments. The window-size line is optional: omit it to let Chrome use its normal headless default, or set it when responsive breakpoints and image dimensions matter.

Wait for pages that render after navigation

driver.get() does not guarantee that a JavaScript application has finished fetching and rendering every component. Use an explicit wait tied to the state you need instead of relying on a guessed sleep duration.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1440,1000")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com/dashboard")
    panel = WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-testid='dashboard']"))
    )
    print(panel.text)
finally:
    driver.quit()

Choose a selector or state that represents usable content: an element becoming visible, a loading indicator disappearing, or a specific title or URL. A fixed delay can be useful for a known animation, but it is less reliable when network speed varies.

Choose a predictable viewport

Headless mode and viewport size are separate settings. Add --window-size=WIDTH,HEIGHT when you need deterministic responsive behavior, screenshots, or visual comparisons:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
options.add_argument("--window-size=1440,1000")

A fixed desktop viewport may cause a mobile breakpoint to remain untested. For responsive testing, create separate sessions with representative dimensions rather than assuming one size covers every layout:

for width, height in [(390, 844), (768, 1024), (1440, 1000)]:
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument(f"--window-size={width},{height}")
    driver = webdriver.Chrome(options=options)
    try:
        driver.get("https://example.com")
        print(width, driver.title)
    finally:
        driver.quit()

Let Selenium Manager handle the driver, or pin it yourself

Default: Selenium Manager

webdriver.Chrome(options=options) is usually sufficient. Selenium invokes its bundled Selenium Manager when it cannot find a usable driver. This avoids adding a separate driver-manager package and reduces manual downloads, but the initial resolution may need network and proxy access.

Manual driver with Service

Use Selenium 4’s Service object when your organization pins an executable, stores drivers in a controlled directory, or runs without download access:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
service = Service("/path/to/chromedriver")

driver = webdriver.Chrome(service=service, options=options)
try:
    driver.get("https://example.com")
    print(driver.title)
finally:
    driver.quit()

Do not use the removed executable_path constructor argument. Chrome and ChromeDriver should have matching major versions. If Chrome updates and a manually installed driver stops working, verify both versions or remove the stale executable and let Selenium Manager resolve a match.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Select an alternate Chrome binary

Leave the binary unset when Chrome is installed conventionally. For a custom installation, set the binary location before creating the driver:

options = webdriver.ChromeOptions()
options.binary_location = "/opt/chrome/chrome"
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)

The path must point to an actual Chrome or Chromium binary visible to the process. A driver path and a browser binary path solve different problems: Service selects the driver executable, while binary_location selects the browser.

Control how long navigation waits

Selenium’s page-load strategy determines when navigation returns:

Strategy Returns after Use when Risk
normal (default) The load event You want the conservative default It can wait longer than a single-page app’s useful content requires
eager DOMContentLoaded You have explicit waits for application content Images and other resources may still be loading
none The initial page download You manage every readiness condition yourself Interactions can be flaky without robust waits

Set a strategy through capabilities only when you have matching waits:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.page_load_strategy = "eager"
driver = webdriver.Chrome(options=options)

For most scripts, keep normal and add explicit waits. Faster strategies are useful for specialized workflows, not as a substitute for knowing when the page is ready.

Use cleanup that survives failures

Always put driver.quit() in finally. It closes the WebDriver session and prevents browser processes from accumulating when navigation, element lookup, or application code fails.

driver = webdriver.Chrome(options=options)
try:
    # navigation and test work
    pass
finally:
    driver.quit()

If you create several drivers in a loop, close each one before creating the next unless you intentionally need concurrent sessions. Reusing one session is generally cheaper than starting a new browser for every URL, while separate sessions provide isolation for cookies, local storage, and viewport settings.

Run headless Chrome in CI or a container

Confirm browser availability

Check that the image contains Chrome or Chromium, or that Selenium Manager is permitted to download it. A minimal Python installation alone is not enough.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Allow resolution traffic

On the first run, Selenium Manager may need to contact remote endpoints to discover and download a driver or browser. Configure the CI proxy and certificate policy, or preinstall and pin the required assets for an offline worker.

Check native dependencies

Container failures can come from missing shared libraries, fonts, or other OS packages. These vary by Linux distribution and image. Diagnose the container’s browser-startup error rather than adding unrelated Chrome flags automatically.

Be cautious with broad flags

Some examples add --no-sandbox. The basic headless workflow does not require it. Add such a flag only when your runtime specifically needs it and your security policy accepts the trade-off.

Troubleshoot common failures

Chrome fails to start

Verify that Chrome is installed or that browser management is enabled, then check the container’s system libraries, executable permissions, and available network access. A headless argument cannot fix a missing binary or dependency.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“This version of ChromeDriver only supports Chrome version …”

The driver and browser major versions do not match. Remove the stale manually installed driver and let Selenium Manager resolve one, or install a driver whose major version matches Chrome and pass it through Service.

A visible window still appears

Confirm that the exact options object passed to webdriver.Chrome(options=options) contains options.add_argument("--headless=new"). Setting an unused options object, or relying on the removed options.headless property, has no effect.

Browser processes remain after the script exits

Ensure every code path reaches driver.quit(), preferably through finally. Also check that an exception is not terminating the process before the driver is assigned; initialize and clean up each session in a controlled scope.

An element is intermittently missing

Navigation completion may precede application rendering. Add an explicit wait for the element or state you actually need, increase the timeout only when the page legitimately takes longer, and verify that the selector is stable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Selenium Manager cannot resolve a driver

Check outbound network and proxy access, custom browser locations, offline policy, and stale driver files. If downloads are prohibited, install a compatible browser and driver in the image and configure their paths explicitly.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a rendered screenshot or PDF rather than browser automation, ScreenshotNeo provides a single HTTP request. It accepts consent banners like a visitor, removes more than 60 known consent platforms plus newsletter popups and chat widgets before capture, and lets you turn each cleanup step off. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with the result identified by X-Page-Verdict and X-Billed headers.

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 data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

See the ScreenshotNeo API documentation for request options. The service also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Features include full-page and element capture, device presets, custom viewport and retina scale, PDF paper settings, custom CSS and JavaScript, clicks, selector waits, network-idle waits, request blocking, cookies, headers, authorization, timezone and geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account to try it without adding a card.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I run headless Chrome and still inspect the DOM?

Yes. Headless mode removes the visible window, not the WebDriver or JavaScript environment. You can read page source, locate elements, execute scripts, and collect console or network diagnostics using Selenium APIs.

Should I use Chrome or Chromium with Selenium?

Either can work when the browser binary and matching driver are available. If the executable is nonstandard, set options.binary_location; otherwise let Selenium discover the installed browser.

Is a fixed window size required for headless mode?

No. --window-size is optional. Add it only when you need repeatable responsive layout, screenshots, or viewport-dependent behavior.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.