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.

Set a download policy and a writable destination before you trigger the download. In current Chrome DevTools Protocol (CDP), send Browser.setDownloadBehavior with behavior: "allow" and a downloadPath. In Selenium, use the equivalent API exposed by your language binding, then wait for the download to finish before opening the file. Headless mode does not configure downloads by itself.

What you must configure

A reliable headless download has four parts:

  1. Launch Chrome or Chromium with the headless mode supported by your installed version.
  2. Configure the active browser or browser context to allow downloads.
  3. Provide an existing directory that the Chrome process can write to.
  4. Start the download and wait for completion before reading, moving or uploading the file.

The CDP reference describes Browser.setDownloadBehavior as “Set the behavior when downloading a file.” The method and its event names are documented in the Chrome DevTools Protocol Browser domain.

Choose a download policy with CDP

Browser.setDownloadBehavior is a browser-level command. Its supported behavior values in the current reference are:

Behavior Effect Path requirement
deny Reject downloads. None stated.
allow Allow downloads to the configured directory. downloadPath is required.
allowAndName Allow downloads while letting the browser assign its download name. downloadPath is required.
default Use the browser’s default download behavior. Not a deterministic automation setup.

When you use allow or allowAndName, create the directory first and pass an absolute path where possible. In containers, that directory must be writable by the user running Chrome, not merely by the user who launched the test on the host.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
HP 14" HD Chromebook Laptop for Students, Intel Quad-Core N4120(> N4020), 4GB RAM, 64GB eMMC, WiFi, Webcam, HDMI, USB-A&C, 14 Hours Battery Life, Zoom, Chrome OS, CUE Accessories
  • Intel Celeron N4120: 4 Cores & Threads, 1.1GHz Base Clock, Up to 2.6GHz Boost Clock, 4MB Cache, Intel UHD Graphics 600. The perfect combination of performance, power consumption, and value helps your device handle multitasking smoothly and reliably with four processing cores to divide up the work.
  • 14" HD Display: 14.0-inch diagonal, HD (1366 x 768), micro-edge, anti-glare. See your digital world in a whole new way. Enjoy movies and photos with the great image quality and high-definition detail of 1 million pixels.
  • Memory & Storage: 4 GB LPDDR4x & 64 GB eMMC Storage. Adequate high-bandwidth RAM to smoothly run multiple applications and browser tabs all at once. An embedded multimedia card provides reliable flash-based storage.
  • Ports:2 x USB 3.0 Type-A,1 x USB 3.0 Type-C,1 x HDMI,1 x Headphone Jack
  • Chrome OS: Chromebook is a computer for the way the modern world works, with thousands of apps. Enjoy the seamless simplicity that comes with Google Chrome and Android apps, all integrated into one laptop. It’s fast, simple, and secure.

The command can also be associated with a browser context when your CDP client exposes that parameter. Keep the scope consistent with the page that starts the download; setting a policy on one context does not automatically configure an unrelated context.

Selenium with JavaScript

The Selenium JavaScript Chromium API documents setDownloadPath(path). It validates that the path is a directory and sends the older Page.setDownloadBehavior command with allow. Use the API that matches your installed Selenium binding and Chrome/ChromeDriver versions; do not assume this wrapper exists in every language. See the Selenium JavaScript Chromium API documentation.

const fs = require('node:fs/promises');
const path = require('node:path');
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

(async function downloadInHeadlessChrome() {
  const downloadDir = path.resolve(process.cwd(), 'downloads');
  await fs.mkdir(downloadDir, { recursive: true });

  const options = new chrome.Options();
  options.addArguments('--headless=new', '--no-sandbox');

  const driver = await new Builder()
    .forBrowser('chrome')
    .setChromeOptions(options)
    .build();

  try {
    await driver.setDownloadPath(downloadDir);
    await driver.get('https://example.test/report');
    await driver.findElement({ css: 'a[data-download="report"]' }).click();

    const deadline = Date.now() + 90_000;
    let files;
    do {
      files = await fs.readdir(downloadDir);
      const partial = files.some(name => name.endsWith('.crdownload'));
      if (files.length > 0 && !partial) break;
      await new Promise(resolve => setTimeout(resolve, 250));
    } while (Date.now() < deadline);

    if (!files || files.length === 0 || files.some(name => name.endsWith('.crdownload'))) {
      throw new Error('The download did not complete before the timeout');
    }
    console.log('Downloaded:', files);
  } finally {
    await driver.quit();
  }
}());

Replace the example URL and selector with your application. The directory check is intentional: a click only starts a download; it does not prove that the final file has been written.

Selenium with Python and a direct CDP command

Python Selenium exposes CDP commands through execute_cdp_cmd. The following uses the browser-level command documented by Chrome. Verify that your Selenium, ChromeDriver and Chrome versions support it; if your binding exposes a dedicated download API, that API may be preferable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from pathlib import Path
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

DOWNLOAD_DIR = Path.cwd() / "downloads"
DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)

options = Options()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")

driver = webdriver.Chrome(options=options)
try:
    driver.execute_cdp_cmd(
        "Browser.setDownloadBehavior",
        {
            "behavior": "allow",
            "downloadPath": str(DOWNLOAD_DIR),
        },
    )
    driver.get("https://example.test/report")
    driver.find_element("css selector", "a[data-download='report']").click()

    deadline = time.monotonic() + 90
    while time.monotonic() < deadline:
        entries = list(DOWNLOAD_DIR.iterdir())
        if entries and not any(p.name.endswith(".crdownload") for p in entries):
            break
        time.sleep(0.25)
    else:
        raise TimeoutError("The download did not complete")

    print([p.name for p in DOWNLOAD_DIR.iterdir()])
finally:
    driver.quit()

Some deployments still use a Selenium wrapper that sends Page.setDownloadBehavior instead. That is an API/version detail, not a guarantee that the same call is portable across Selenium languages.

Wait for the file, not just the click

Filesystem polling

Polling is simple and works when you control the download directory. Chrome commonly uses a temporary .crdownload suffix while bytes are arriving. Wait until the temporary file disappears, then verify that the expected file exists and has a sensible size. If several downloads can run concurrently, record the directory contents before the click and select only newly created files.

DevTools download events

The Browser domain documents Browser.downloadWillBegin and Browser.downloadProgress. A progress event reports states such as in progress, completed or canceled, and a completed event may include a file path. The documentation cautions that the path is not guaranteed to be set and does not guarantee that the file exists, so confirm the file on disk before consuming it.

Prevent false positives

  • Do not treat an HTTP response to the click as proof that the file is complete; the browser may still be streaming it.
  • Do not reuse a directory containing an old file with the same name unless you compare modification time or remove the old file first.
  • Use a timeout appropriate to the file size and network, and report the URL, selector and directory when the timeout fires.
  • For multiple downloads, give each test an isolated directory to avoid races.

Headless mode and Chrome versions

The Chrome developer guide demonstrates --headless=new with Selenium, but command-line examples such as --dump-dom and --print-to-pdf are not a complete download configuration. You still need the download policy and destination described above. See Chrome Headless mode.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
ASUS 2026 15" FHD IPS Chromebook, Intel Processor Up to 2.80GHz, 4GB DDR4, 128GB Storage, HDMI, Super-Fast WiFi, Chrome OS, Pastel Silver (Renewed)
  • Intel Processor Up to 2.80GHz, 4GB DDR4, 128GB Storage
  • 15" FHD IPS Display, Intel UHD Graphics
  • 1x USB Type C, 1 x USB Type A, 1x Headphone/Microphone Combo Jack, HDMI
  • Fast WiFi and Bluetooth, Integrated Webcam
  • Chrome OS, AC Charger Included, Pastel Silver

There is an important version boundary: Chromium’s Headless README says that from milestone M132, the old Headless functionality is no longer part of the Chrome binary and --headless=old has no effect. Users who specifically need that old implementation are directed to chrome-headless-shell. The README is at Chromium Headless. Check the installed browser, driver and Selenium versions together; the cited material does not provide a complete compatibility matrix.

Common failures and fixes

“Download is blocked” or nothing appears

Usually the policy was never set, it was set after the click, or it was applied to a different browser context. Create the directory, configure the active driver immediately after launch, and only then navigate and click.

“downloadPath must be a directory”

The path does not exist, points to a file, or is not visible inside the container. Create it with the test process, pass an absolute path, and check ownership and permissions from inside the runtime where Chrome executes.

The script finishes before the file is usable

A successful click or a completed CDP event is not a substitute for a filesystem check. Wait for the temporary suffix to disappear, then check that the final path exists. Remember that the protocol may omit a path in its event.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Lenovo Chromebook 2-in-1 - Lightweight Laptop - Google Gemini - Intel® N150 CPU - 14" WUXGA IPS Touchscreen Display - 4GB RAM - 128GB UFS Storage - Integrated Intel® Graphics - Luna Grey
  • THE BETTER WAY TO LAPTOP – Imagine a Chromebook that’s as flexible as your day: thin and lightweight with built-in Google apps and stress-free security.
  • TAKE HITS KEEP MOVING – Sleek, light, and built to last- the Chromebook 2-in-1 is just 0.69” thick and 3.3lbs. Enjoy long-lasting battery life, fast charging, and military-grade durability for nonstop productivity wherever life takes you.
  • PERFORMANCE THAT MATCHES YOUR HUSTLE – Fuel your ideas with an Intel Core processor and 128GB storage. Boot up in under 10 seconds to start the day powerfully efficient.
  • FLEX YOUR CREATIVITY ANYWHERE, ANYTIME – Create, work, or unwind your way with a versatile 2-in-1 design. Flip easily between laptop, tent, and tablet modes with a responsive touchscreen built for flexibility.
  • BRILLIANT VIEWS AND IMMERSIVE AUDIO – See, hear, and create with awesome clarity. The WUXGA display brings rich detail to your work and play, while audio tuned by Waves MaxxAudio provides immersive, balanced sound.

The command is “unknown”

Your Selenium binding or browser may not expose the same command name. The JavaScript wrapper documented by Selenium sends Page.setDownloadBehavior, while the current CDP reference documents Browser.setDownloadBehavior. Check the API documentation for your exact Selenium and Chrome versions rather than copying a call from another binding.

Headless flag warnings after a browser upgrade

Confirm whether your installation supports --headless=new. Do not rely on --headless=old with Chrome M132 or later; the old implementation was removed from the Chrome binary according to Chromium’s README.

Authentication or a missing download link

Download policy does not log a user into your application. Establish the session, cookies or authentication headers in the browser first, then verify that the link or button is present. If the application creates a download only after JavaScript runs, wait for that UI state before clicking.

Security, reliability and CI notes

  • Use a per-run directory and delete it after collecting the artifact. This prevents one test from consuming another test’s file.
  • Never make a shared, writable system directory the destination for untrusted downloads.
  • Keep the browser and driver versions aligned with the Selenium binding. A protocol method can be present in documentation but unavailable through an older client.
  • For large files, increase the timeout instead of polling more aggressively. A short polling interval does not accelerate the network transfer.
  • Capture diagnostic information on failure: browser version, headless flag, target URL, download directory, observed filenames and the last download event.
  • If you need a stable filename, inspect the final browser-created name after completion; redirects and server headers can change it.
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 actual requirement is a rendered screenshot or PDF of a URL rather than downloading an application file, ScreenshotNeo returns it with one request. Its API accepts options for full-page capture, lazy-loaded images, CSS selectors, viewport and device settings, PDF output, custom CSS or JavaScript, waits, request blocking, cookies and headers. The documentation is at https://screenshotneo.com/docs/.

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.
Best Value
HP Chromebook 14 Laptop, Intel Celeron N4120, 4 GB RAM, 64 GB eMMC, 14" HD Display, Chrome OS, Thin Design, 4K Graphics, Long Battery Life, Ash Gray Keyboard (14a-na0226nr, 2022, Mineral Silver)
  • FOR HOME, WORK, & SCHOOL – With an Intel processor, 14-inch display, custom-tuned stereo speakers, and long battery life, this Chromebook laptop lets you knock out any assignment or binge-watch your favorite shows..Voltage:5.0 volts
  • HD DISPLAY, PORTABLE DESIGN – See every bit of detail on this micro-edge, anti-glare, 14-inch HD (1366 x 768) display (1); easily take this thin and lightweight laptop PC from room to room, on trips, or in a backpack.
  • ALL-DAY PERFORMANCE – Reliably tackle all your assignments at once with the quad-core, Intel Celeron N4120—the perfect processor for performance, power consumption, and value (2).
  • 4K READY – Smoothly stream 4K content and play your favorite next-gen games with Intel UHD Graphics 600 (3) (4).
  • MEMORY AND STORAGE – Enjoy a boost to your system’s performance with 4 GB of RAM while saving more of your favorite memories with 64 GB of reliable flash-based eMMC storage (5).
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie and consent banners, newsletter popups and chat widgets are removed before the shot; each cleanup step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed. Response headers identify the page verdict and whether it was billed.
  • An MCP server provides 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 shots; every feature is available on every plan.

Create a free ScreenshotNeo account to try 1,000 screenshots a month without adding a card.

Frequently Asked Questions

Can I download files with Chrome headless without Selenium?

Yes. Any CDP client that can send the Browser domain command can configure the policy, start the download and monitor its events. The exact connection and event-handling code depends on that client.

Is a completed download event enough to trust the artifact?

No. The protocol documentation says a reported path may be absent and does not guarantee that the file exists. Confirm the final file on disk before processing it.

Which headless flag should a new test suite use?

Use the headless mode supported by the Chrome version installed in your environment, commonly --headless=new in current Selenium examples. Do not expect --headless=old to work with Chrome M132 and later.

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

Why does the same Selenium code work in one language but not another?

Selenium bindings expose different helper methods and may send different CDP commands. Match the API to the binding and version you actually install, and verify the browser and driver versions as a set.

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.