Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Set Chrome’s download directory, but do not treat that setting as an “ never overwrite” switch. Selenium’s download.default_directory preference only chooses where Chrome saves files. To prevent collisions when a site repeatedly returns the same filename, isolate each run in its own directory or wait for each download to finish and rename it in Python before starting the next one. ChromeDriver does not automatically wait for downloads to complete, so completion handling is part of a reliable solution.
What actually causes the overwrite
When a download response supplies a filename such as report.pdf, Chrome resolves that name inside its configured download directory. If your script triggers the same download again, both operations target the same directory and suggested name. The directory preference does not document a duplicate-name policy, and ordinary Selenium Python options do not expose a portable “always append (1)” or “always replace” switch.
That distinction matters because several similarly named controls belong to different APIs:
download.default_directoryis a Chrome preference for the destination folder.- The Chrome extension downloads API has a
conflictActionsetting withuniquify,overwrite, andprompt. That API is for extension-managed downloads, not a standard Selenium preference. - Chrome DevTools Protocol (CDP) has an experimental
allowAndNamemode that saves with download GUIDs. It can avoid collisions but changes the filename and requires protocol-specific code.
For most Selenium jobs, filesystem isolation or explicit Python naming is easier to understand, test, and maintain.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Option 1: Give every run its own absolute directory
A unique directory per run is the safest default. The server’s original filename remains intact, and concurrent workers cannot overwrite one another’s files.
from pathlib import Path
from uuid import uuid4
from selenium import webdriver
base_dir = Path("./selenium-downloads").resolve()
run_dir = base_dir / f"run-{uuid4().hex}"
run_dir.mkdir(parents=True, exist_ok=False)
options = webdriver.ChromeOptions()
options.add_experimental_option(
"prefs",
{
"download.default_directory": str(run_dir),
# Keep the browser from asking for a location interactively.
"download.prompt_for_download": False,
},
)
driver = webdriver.Chrome(options=options)
try:
driver.get("https://example.com/download-page")
# Locate and click the real download control here.
# Example: driver.find_element(By.CSS_SELECTOR, "a.download").click()
finally:
driver.quit()
print(f"Files for this run are in {run_dir}")
Use a normal, writable directory with an absolute path. ChromeDriver documentation warns that some locations are restricted; Desktop and, on Linux, the home directory are specifically mentioned examples, and the blocked list can change. A task-specific subdirectory avoids those special cases.
Use one directory per file instead of one per run when a run downloads several unrelated artifacts and you need a simple one-to-one association. If you retain run directories, clean them with a separate retention job after your process has verified the files.
Option 2: Wait for completion, then rename in Python
If all downloads must live in one directory, make naming an explicit application decision. Trigger one download, wait until Chrome has finished writing it, rename it, and only then start the next download.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
from pathlib import Path
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
DOWNLOAD_DIR = Path("./downloads").resolve()
DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)
options = webdriver.ChromeOptions()
options.add_experimental_option(
"prefs",
{"download.default_directory": str(DOWNLOAD_DIR)},
)
driver = webdriver.Chrome(options=options)
def wait_for_new_download(folder: Path, before: set[str], timeout: float = 90) -> Path:
"""Return the newly completed file, or raise TimeoutError."""
deadline = time.monotonic() + timeout
partial_suffixes = (".crdownload", ".tmp")
while time.monotonic() < deadline:
current = {p.name for p in folder.iterdir() if p.is_file()}
new_names = current - before
candidates = [folder / name for name in new_names]
completed = [
p for p in candidates
if p.suffix not in partial_suffixes
and not p.name.endswith(partial_suffixes)
]
if completed and not any(
(folder / name).name.endswith(partial_suffixes)
for name in new_names
):
# If several files appeared, choose the most recently modified one.
return max(completed, key=lambda p: p.stat().st_mtime)
time.sleep(0.25)
raise TimeoutError(f"No completed download appeared within {timeout:g}s")
try:
driver.get("https://example.com/download-page")
before = {p.name for p in DOWNLOAD_DIR.iterdir() if p.is_file()}
driver.find_element(By.CSS_SELECTOR, "a.download").click()
downloaded = wait_for_new_download(DOWNLOAD_DIR, before)
destination = DOWNLOAD_DIR / "invoice-2026-09.pdf"
downloaded.replace(destination) # intentional replacement only after completion
finally:
driver.quit()
Chrome commonly uses a .crdownload suffix while a file is being written. Polling for a new file and the disappearance of the partial file is a practical script-level pattern, not a guarantee that every site or browser version uses exactly the same temporary suffix. For unpredictable server filenames, the before/after directory snapshot avoids guessing the name.
Rank #2
Replacing the latest copy intentionally
If your requirement is “keep only the newest report,” do not rely on an undocumented Chrome preference. After completion, validate the file (for example, size or MIME type), then replace a known destination with Python’s Path.replace(). That makes replacement visible in code and lets you add checks, logging, or backups.
Choosing an approach
| Approach | Original server filename | Collision protection | Implementation effort | Portability |
|---|---|---|---|---|
| Directory per run or file | Preserved | Strong isolation, including parallel sessions | Low | Uses documented ChromeOptions behavior |
| Wait, then Python rename | Preserved until your rename | Strong if completion and identification are correct | Medium | Works in a shared directory, but requires polling logic |
CDP allowAndName |
No; GUID-based name | Strong at the saved-file level | High | Experimental and version-sensitive |
Extension conflictAction |
Depends on extension behavior | Defined by extension API | Not applicable to ordinary Selenium setup | Wrong interface for a normal WebDriver download |
Use per-run directories for parallel jobs and test suites. Use rename-after-completion when an existing pipeline requires one shared folder or a business-specific filename. Consider CDP only when GUID naming and protocol coupling are acceptable.
Make the completion check reliable
Do not quit immediately
ChromeDriver explicitly does not automatically wait for a download to finish. Calling driver.quit() directly after a click can terminate the browser while the file is incomplete. Wait for the expected file or a detected new file before quitting.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Set a realistic timeout
Choose a timeout based on expected file size, network conditions, and your CI environment. On timeout, preserve the directory for diagnosis, list its contents, and record browser and driver versions. Avoid an unbounded sleep: it hides failures and makes test runs slow.
Handle concurrent workers
Never let independent Selenium sessions share a download directory unless you coordinate access. A before/after snapshot can otherwise attribute another worker’s file to the wrong click. A unique directory created before each session removes that race.
Verify the result
After a file appears, check that it is not empty and has the expected extension or content signature. A completed HTML error page can look like a successful download if the server returned an error document with a misleading filename.
Advanced: CDP GUID-based naming
The Chrome DevTools Protocol documents an experimental Browser.setDownloadBehavior command with an allowAndName option. With a download path configured, Chrome names files using download GUIDs, which avoids duplicate target names. The trade-off is that the convenient server-provided filename is lost, and the command is experimental. Selenium’s support for sending CDP commands and the exact command shape can vary with Chrome and Selenium versions, so validate it against the versions used by your application before adopting it.
This is not a reason to present allowAndName as a stable replacement for the standard ChromeOptions recipe. For a portable Python script, isolate directories or rename completed files yourself.
Version and environment prerequisites
- Use current Selenium Python syntax: create
webdriver.ChromeOptions(), add preferences, and pass it aswebdriver.Chrome(options=options). - Keep Chrome and ChromeDriver major versions aligned. A mismatch can cause session creation errors or unexpected behavior before download logic runs.
- Ensure the configured directory exists and the account running the test can write to it.
- Run headless and headed jobs with the same download-directory setup; do not assume a developer’s interactive profile settings are present in CI.
- Keep each test’s browser profile and download directory separate when tests run in parallel.
Troubleshooting common failures
The file still appears as report (1).pdf
That is Chrome’s own collision handling, not evidence that Selenium selected a documented policy. Check whether an older file remains in the directory and whether another session is downloading concurrently. If you need deterministic names, use a fresh directory or rename the completed file in Python.
The configured folder is empty
Print the resolved path and verify it exists and is writable. Confirm that the preference is passed before driver creation. Avoid restricted locations such as Desktop or the Linux home directory, and check that the click actually starts a download rather than opening a new tab or navigating to an error page.
The script times out while a .crdownload remains
The transfer may still be running, the response may require authentication, or the page may have triggered a bot check. Increase the timeout only when the file size and network justify it. Otherwise inspect browser logs, response behavior, and session credentials. Do not rename or move the partial file.
driver.quit() loses the file
Move the quit call after your completion wait. ChromeDriver does not wait automatically, so a successful click is not a completed filesystem operation.
Parallel tests overwrite one another
Create a unique directory before each webdriver.Chrome instance and pass that path in its preferences. Do not use a shared global downloads folder for workers.
A CDP command fails
Check Chrome/Selenium compatibility and remember that allowAndName is experimental. If you need the original filename or stable behavior, return to the documented ChromeOptions directory setting and Python-side naming.
You expected Selenium’s enable_downloads property to choose a conflict policy
The Selenium Chromium options API exposes download enablement, but that surface does not document duplicate-name selection. It does not replace the isolation and renaming patterns above.
Best Value
Or skip the browser setup
If your goal is to obtain rendered screenshots rather than exercise a browser download workflow, ScreenshotNeo provides a website screenshot API and MCP server. It accepts the consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—let Claude, Cursor, or another MCP client request captures directly.
One GET request returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for all options.
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}`);
ScreenshotNeo includes full-page captures with lazy images loaded, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, click-before-capture actions, selector hiding, waits for selectors, delays or network idle, request and resource blocking, custom headers, cookies, user agents and authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan, and annual billing provides two months free. Create a free ScreenshotNeo account to start.
Final implementation checklist
- Resolve a dedicated download path to an absolute location.
- Create a separate directory per run or per file when isolation matters.
- If sharing a directory, snapshot before the click, wait for completion, and rename only after the partial file disappears.
- Keep
driver.quit()after the completion check. - Align Chrome and ChromeDriver major versions and verify write permissions.
- Treat extension conflict actions and experimental CDP naming as separate mechanisms, not Selenium preferences.
Frequently Asked Questions
Can I set a Selenium preference that always saves duplicates as “file (1)” ?
Not as a documented ordinary Selenium Python preference. Use separate directories or rename completed downloads in Python. The extension downloads API has its own conflict actions, but that is a different interface.
Why does a download exist but remain unusable?
Chrome may still be writing it, commonly with a .crdownload suffix. Wait for the partial file to disappear before moving, renaming, validating, or quitting the driver.
Is CDP allowAndName suitable for every project?
No. It is experimental, uses GUID-based names instead of the server filename, and should be validated against the exact Chrome and Selenium versions in your environment.
Quick Recap
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.
Recommended Free Tools

