Download Files in Chrome and Firefox Using Selenium Python


Automating file downloads is a common requirement in Selenium testing, especially when verifying reports, invoices, or data exports. Handling downloads through a browser is different from interacting with page elements because downloads are managed by the browser itself, not the DOM.
This creates challenges like controlling the save location, bypassing pop-ups, and confirming that the file has been saved correctly. Selenium with Python allows you to configure browser settings for Chrome and Firefox so that files can be downloaded automatically without manual steps.
This article covers how to download files in Selenium Python across different file types and browsers.
What is File Download Automation in Selenium with Python?
File download automation means configuring the browser so that it saves files directly to a specified location during a Selenium test. Normally, when you click a download link in Chrome or Firefox, a dialog box appears asking where to save the file. Selenium alone cannot handle this dialog because it is controlled by the operating system, not the browser’s DOM.
With Python bindings, you can pass special browser preferences and options to WebDriver. These settings decide how files are handled when a download is triggered. For example, you can disable the “Save As” dialog, set a default download folder, and define file handling rules for formats like PDF, CSV, or ZIP.
Why Automate File Downloads in Selenium Testing
In testing, file downloads are often checkpoints rather than end goals. Reports, data exports, or logs must be validated to confirm accuracy. Handling these manually disrupts the flow and introduces inconsistency, while automation makes the process repeatable and reliable.
Here are some more reasons automation is important for downloads:
- Consistency across environments: When running tests on local machines, CI pipelines, or remote grids, you need the same download behavior. Configuring downloads removes uncertainty caused by browser prompts or user intervention.
- Validation of critical workflows: Many applications generate files that must be verified. For example, confirming a PDF invoice contains correct data or ensuring a CSV export has the expected structure. Automation makes this validation part of the test, not a separate step.
- Time and resource efficiency: Without automation, testers spend time manually saving and checking files. Automated downloads integrate this directly into the test suite, reducing extra steps and human error.
- Scalability in regression testing: When hundreds of test cases involve file downloads, manual verification is not practical. Automated downloads ensure that every file across different test runs is handled the same way.
- Support for headless execution: In many CI/CD pipelines, browsers run in headless mode. File download automation is the only way to capture and validate these downloads because there is no manual way to interact with dialogs in a headless session.
- Audit and compliance needs: In regulated industries, proof of correct file generation is critical. Automated download and verification can act as evidence that the system is generating files as expected.
How to Save Files to a Specific Folder in Chrome with Selenium
By default, Chrome asks where to save a file each time you trigger a download. Since Selenium cannot interact with system dialogs, you need to configure Chrome options so that files are saved automatically to a defined folder.
This is done using the prefs dictionary in ChromeOptions. You can set the download directory, disable pop-ups, and tell Chrome to handle specific file types without prompting.
Here is a basic example in Python:
from selenium import webdriver
import os
# Set download path
download_dir = os.path.join(os.getcwd(), "downloads")
options = webdriver.ChromeOptions()
prefs = {
"download.default_directory": download_dir,
"download.prompt_for_download": False,
"download.directory_upgrade": True,
"safebrowsing.enabled": True
}
options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(options=options)
driver.get("https://file-examples.com/index.php/sample-documents-download/")
# Example: clicking a download link
download_link = driver.find_element("xpath", "//a[contains(text(),'Download sample DOC file')]")
download_link.click()
In this setup:
- download.default_directory tells Chrome where to save files.
- download.prompt_for_download set to False bypasses the Save As dialog.
- download.directory_upgrade ensures Chrome updates the directory if it already exists.
- safebrowsing.enabled avoids Chrome blocking the download.
With this configuration, any file triggered by Selenium is stored in the downloads folder without user interaction.
How to Save Files to a Specific Folder in Firefox with Selenium
Like Chrome, Firefox also prompts users with a dialog when a download starts. To automate file downloads, you need to pass preferences through FirefoxProfile or Options. These preferences control where files are saved and how different file types are handled.
Here is a working example in Python:
from selenium import webdriver
import os
# Set download path
download_dir = os.path.join(os.getcwd(), "downloads")
profile = webdriver.FirefoxProfile()
profile.set_preference("browser.download.folderList", 2) # 2 = custom folder
profile.set_preference("browser.download.dir", download_dir)
profile.set_preference("browser.helperApps.neverAsk.saveToDisk",
"application/pdf,text/csv,application/zip,image/png")
profile.set_preference("pdfjs.disabled", True) # Avoid opening PDFs in browser
driver = webdriver.Firefox(firefox_profile=profile)
driver.get("https://file-examples.com/index.php/sample-documents-download/")
# Example: clicking a download link
download_link = driver.find_element("xpath", "//a[contains(text(),'Download sample CSV file')]")
download_link.click()
Key settings explained:
- browser.download.folderList = 2 means use a custom directory.
- browser.download.dir specifies the download path.
- browser.helperApps.neverAsk.saveToDisk lists MIME types that should be saved automatically without prompts.
- pdfjs.disabled = True prevents Firefox from opening PDFs in a new tab.
With these preferences, Firefox saves files silently in the specified folder.
MIME Types in Firefox WebDriver for File Downloads
When Firefox starts a download it uses the server provided MIME type to decide how to handle the file. If the MIME type is not accepted by browser.helperApps.neverAsk.saveToDisk Firefox will show a prompt or open a helper application. That makes correct MIME handling central to silent, automated downloads.
Here is what to consider before you set preferences, and then the settings you should use.
- Servers may return accurate MIME types, incorrect MIME types, or a generic application/octet-stream. Tests must handle all three cases.
- If a download URL is generated dynamically or requires authentication, you may not be able to predict the MIME type from the link alone.
- You can proactively include broad types such as application/octet-stream to reduce prompts, but be careful with security policies on CI or shared runners.
- When possible, inspect the response headers with an authenticated HEAD request to confirm the content-type before the browser attempts the download.
Common MIME types to include for test automation
- application/pdf for PDFs
- text/csv for CSV files
- application/vnd.ms-excel and application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for XLS and XLSX
- application/zip for ZIP archives
- image/png, image/jpeg, image/gif for common image types
- text/plain for plain text files
- application/octet-stream for generic binary streams when server does not set a precise type
- application/vnd.ms-powerpoint and application/vnd.openxmlformats-officedocument.presentationml.presentation for PPT/PPTX
Example: set these preferences in Python with Selenium and add some safety prefs
from selenium import webdriver
import os
download_dir = os.path.join(os.getcwd(), "downloads")
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.download.folderList", 2)
fp.set_preference("browser.download.dir", download_dir)
# Use a broad list that covers expected file types
fp.set_preference("browser.helperApps.neverAsk.saveToDisk",
"application/pdf,application/octet-stream,"
"text/csv,application/zip,"
"application/vnd.ms-excel,"
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,"
"image/png,image/jpeg,text/plain")
fp.set_preference("pdfjs.disabled", True)
fp.set_preference("browser.download.useDownloadDir", True)
fp.set_preference("browser.download.manager.showWhenStarting", False)
driver = webdriver.Firefox(firefox_profile=fp)
Handling unknown or dynamic MIME types
- If you control the API that generates the file, return an accurate Content-Type header.
- If you do not control the server, do a HEAD request to the download URL before opening it in the browser. Use the returned Content-Type header to add the MIME to browser.helperApps.neverAsk.saveToDisk at runtime. This works for authenticated URLs if you replicate the same auth headers the browser will use.
- If the server returns application/octet-stream, include application/octet-stream in your never-ask list. That covers many servers that serve files as generic streams.
Downloading PDF, CSV, Images, and ZIP Files in Selenium
Below are concrete, practical patterns and code you can use to download and verify common file types during Selenium tests. Each subsection states the goal, gives a compact Selenium configuration if needed, then shows how to validate the downloaded file on disk.
Use these as reusable building blocks in real test suites.
1. Common setup and utilities
Before examples, use a consistent helper that creates a clean download folder and waits for the file to appear. Put this in your test utilities and reuse it across browsers.
import os
import time
import shutil
from pathlib import Path
DEFAULT_WAIT_TIMEOUT = 30 # seconds
POLL_INTERVAL = 0.5 # seconds
def make_download_dir(base="downloads"):
path = Path(os.getcwd()) / base
if path.exists():
# clean prior artifacts for deterministic tests
shutil.rmtree(path)
path.mkdir(parents=True, exist_ok=True)
return str(path)
def wait_for_file(download_dir, filename_partial=None, timeout=DEFAULT_WAIT_TIMEOUT):
"""
Wait until a file appears in download_dir.
If filename_partial provided, match files that contain this substring.
Returns the Path of the first matching file or raises TimeoutError.
"""
deadline = time.time() + timeout
download_dir = Path(download_dir)
while time.time() < deadline:
files = list(download_dir.iterdir())
if filename_partial:
matches = [f for f in files if filename_partial in f.name and f.stat().st_size > 0]
else:
matches = [f for f in files if f.stat().st_size > 0]
if matches:
# pick the newest file
return sorted(matches, key=lambda p: p.stat().st_mtime, reverse=True)[0]
time.sleep(POLL_INTERVAL)
raise TimeoutError(f"No file appeared in {download_dir} within {timeout} seconds")
Use this helper after triggering a download. It avoids brittle sleep and works for headless runs.
2. PDF files
Browsers sometimes open PDFs in a viewer instead of downloading. Also PDFs need content validation, not only existence.
Chrome prefs and Firefox profile examples
# Chrome: ensure PDFs are downloaded instead of opened
chrome_prefs = {
"download.default_directory": download_dir,
"download.prompt_for_download": False,
"plugins.always_open_pdf_externally": True,
}
# Firefox: disable pdfjs
fp.set_preference("pdfjs.disabled", True)
Validate PDFs after download
- Check file exists and the file size is reasonable.
- Open the file with a PDF parser to verify the number of pages or presence of a specific text string.
Example using PyPDF2
from PyPDF2 import PdfReader
def verify_pdf_contains(file_path, expected_text):
reader = PdfReader(file_path)
# quick sanity: at least one page
if len(reader.pages) == 0:
return False
# search pages for expected text
for page in reader.pages:
text = page.extract_text() or ""
if expected_text in text:
return True
return False
3. CSV and other tabular exports
CSV and Excel are common for reports. CSV is easier to validate. Use a CSV parser or pandas to check row counts and headers.
Chrome and Firefox configuration
No special browser setting beyond the download directory is required if the server sends text/csv or application/csv. For Excel you may add MIME types to Firefox neverAsk.saveToDisk.
CSV validation example with pandas
import pandas as pd
def verify_csv_has_columns(file_path, required_columns):
df = pd.read_csv(file_path)
return all(col in df.columns for col in required_columns)
def verify_csv_row_count_min(file_path, min_rows):
df = pd.read_csv(file_path)
return len(df) >= min_rows
4. Images (PNG, JPEG, GIF)
Image downloads are usually straightforward. Validation should include checking image integrity and basic properties like dimensions or format.
Example checks with Pillow
from PIL import Image
def verify_image(file_path, min_width=None, min_height=None, expected_format=None):
with Image.open(file_path) as img:
img.verify() # raises if corrupt
# reopen to access size and format
with Image.open(file_path) as img:
w, h = img.size
fmt = img.format
if expected_format and fmt.upper() != expected_format.upper():
return False
if min_width and w < min_width:
return False
if min_height and h < min_height:
return False
return True
5. ZIP archives
ZIP files can contain multiple files and preserve folder structure. Test steps often need to inspect contents to ensure expected files are present.
Validate ZIP using Python zipfile
import zipfile
def verify_zip_contains(file_path, expected_members):
with zipfile.ZipFile(file_path, 'r') as z:
names = z.namelist()
return all(any(exp in name for name in names) for exp in expected_members)
Extract and validate CSV inside ZIP
def extract_and_verify_csv_in_zip(zip_path, expected_csv_name, required_columns):
with zipfile.ZipFile(zip_path, 'r') as z:
# find the CSV entry
csv_entries = [n for n in z.namelist() if expected_csv_name in n]
if not csv_entries:
return False
# extract to memory or temp folder
with z.open(csv_entries[0]) as csvfile:
df = pd.read_csv(csvfile)
return all(col in df.columns for col in required_columns)
How to Verify if a File Was Successfully Downloaded
A download is only useful if the file is complete and correct. Simply checking for its presence is not enough. Below are the key steps testers usually follow:
- Check for file existence: Confirm the file appears in the download directory and is not empty. Ignore temporary files like .crdownload or .part.
- Wait for completion: Poll the file size until it stops changing to ensure the browser has finished writing.
- Validate filename: Compare the saved name against the expected value from the Content-Disposition header or partial match logic.
- Check integrity: Use a checksum (SHA256 or MD5) or at least verify file size is within expected bounds.
- Inspect content: Parse based on type. For example:
- PDF: check page count or presence of specific text.
- CSV: assert required headers and row counts.
Images: confirm dimensions and format with Pillow. - ZIP: list members and verify required files exist.
- Use isolated directories: Create a fresh download folder per test run to avoid leftover files or collisions.
- Add logging in CI: Capture download directory contents, sizes, and hashes so failures are easier to debug.
Best Practices for Downloading Files with Selenium in Python
When you automate downloads, tests become stable only if file handling is predictable and validation is thorough. Below are the main practices you should follow:
- Download directory: Always create a fresh folder for downloads in each test. Clean it at the start so no old files interfere, and remove it at the end unless you need to archive files for debugging.
- Browser configuration: Set the download folder explicitly in ChromeOptions or FirefoxProfile. Disable the “Save As” dialog and turn off built-in PDF viewers so files are stored directly.
- Completion check: Do not rely on static sleeps. Instead, poll for the file until it appears, check that its size increases, and confirm the size stops changing before proceeding.
- Validation depth: File existence alone is not enough. Add checksum or file size validation, and parse file content with libraries like PyPDF2, pandas, Pillow, or zipfile depending on type.
- MIME handling: In Firefox, whitelist only the MIME types you expect. Avoid a global application/octet-stream unless absolutely necessary, since it hides server misconfigurations.
- Headless runs: Run the same download logic in both headed and headless browsers. Some differences exist, for example PDF handling or how temporary files are created.
- Logging and CI: Capture a snapshot of the download folder on failures, including filenames and sizes. Store it as an artifact in CI pipelines so issues can be diagnosed without re-running the test.
Conclusion
Automating file downloads in Selenium with Python removes manual interruptions and ensures end-to-end workflows are validated. By configuring browser preferences, handling MIME types, and verifying downloaded files thoroughly, testers can build stable suites that catch both functional and content-level issues across formats like PDF, CSV, ZIP, and images.
With BrowserStack, you can execute Selenium download tests on 3,500+ real browsers and devices without local setup. This allows you to confirm downloads behave consistently across versions and platforms and ensure your test coverage matches real-world user conditions.

Contents
- What is File Download Automation in Selenium with Python?
- Why Automate File Downloads in Selenium Testing
- How to Save Files to a Specific Folder in Chrome with Selenium
- How to Save Files to a Specific Folder in Firefox with Selenium
- MIME Types in Firefox WebDriver for File Downloads
- Downloading PDF, CSV, Images, and ZIP Files in Selenium
- 1. Common setup and utilities
- 2. PDF files
- 3. CSV and other tabular exports
- 4. Images (PNG, JPEG, GIF)
- 5. ZIP archives
- How to Verify if a File Was Successfully Downloaded
- Best Practices for Downloading Files with Selenium in Python
- Conclusion
Subscribe for latest updates
Share this article
Related posts





