How to Download Files in Playwright
How to Handle File Downloads in Playwright (With Examples)
File downloads in Playwright look simple on the surface. A click triggers a download, a file gets saved, and the test moves on. That expectation breaks quickly once downloads start behaving differently across browsers, paths are not where they should be, or validations turn flaky.
I have seen tests pass locally and fail in CI just because the download was not captured correctly. In some cases, the file exists but cannot be accessed. In others, the download event is missed entirely, so the test has nothing to verify. These are not edge cases. They show up the moment file downloads become part of real test flows.
The interesting part is Playwright does not treat downloads like regular UI interactions. There is a specific flow behind how downloads are triggered, captured, stored, and accessed. If that flow is not handled correctly, even simple scenarios start failing.
In this guide, I will break down how file downloads actually work in Playwright, how to control where files are saved, and how to reliably validate them in automation tests without introducing flakiness.
How File Downloads Work in Playwright
File downloads in Playwright are not handled like typical UI actions such as clicking a button or typing into an input field. There is an underlying event-driven mechanism that controls how downloads are initiated and captured, and understanding this flow is critical for writing reliable tests.
When a user action triggers a download, for example clicking a download link or button, Playwright does not immediately give access to the file. Instead, it emits a download event that must be explicitly captured. This is where most implementations go wrong, especially when the test tries to interact with the file before Playwright has fully registered the download.
To make this reliable, Playwright introduces a structured flow that ensures the download is properly tracked and accessible.
What Happens When a File is Downloaded
At a high level, the process follows a clear sequence:
- Action triggers download: A user interaction such as clicking a link or submitting a form initiates the download request
- Download event is emitted: Playwright listens for a download event that represents the file being generated
- Temporary storage is used: The file is stored in a temporary location managed by the browser context
- Download object is created: Playwright provides a Download object that gives access to metadata and file handling methods
- File becomes accessible: The file can then be saved, moved, or validated based on the test requirements
This flow ensures that the test does not rely on assumptions about timing or file availability.
Why This Flow Matters in Automation
Without handling downloads through this event-driven approach, tests can easily become unreliable. The main challenges include timing issues, inconsistent file paths, and incomplete downloads.
- Timing issues: If the test tries to access the file before the download event is captured, it may fail intermittently
- Unknown file locations: By default, files are stored in a temporary directory, which makes direct access difficult without explicit handling
- Incomplete downloads: Without waiting for the download to finish, validations may run on partial or missing files
Setting Up the Playwright Environment for File Downloads
File downloads in Playwright rely heavily on how the environment is configured. A missing setup step can lead to downloads that never get captured, files that are hard to locate, or validations that fail inconsistently across local runs and CI pipelines.
A proper setup ensures that Playwright is installed correctly, the environment is validated, and the browser context is configured to handle downloads explicitly. With this in place, download flows become predictable and easier to debug.
Install Playwright for File Download Testing
Start by installing Playwright along with the required browser binaries so tests can run across supported environments and handle downloads consistently.
For JavaScript:
- Initialize project: Set up a Node.js project using npm init
- Install Playwright: Run npm install -D @playwright/test
- Install browsers: Run npx playwright install to download supported browsers
For Python:
- Install package: Use pip install playwright
- Install browsers: Run playwright install to download browser binaries
This step prepares the environment for executing download-related test scenarios.
Verify the Playwright Installation
After installation, confirm that Playwright is running as expected. This step helps catch setup issues early before adding download-specific logic.
- Run a sample test: Execute a basic Playwright test to confirm setup
- Check browser launch: Ensure that browsers such as Chromium start correctly
- Validate test execution: Confirm that tests run successfully in both local and CI environments
For example, running npx playwright test should execute tests successfully. Any failure at this stage points to environment issues that need attention.
Create a Browser Context That Supports File Downloads
Playwright uses isolated browser contexts for each test. To work with file downloads, the context needs to be configured to accept and manage downloads.
- Enable downloads: Set acceptDownloads: true while creating the browser context
- Control file handling: Define how downloaded files are accessed or stored
- Maintain isolation: Each test context manages its own downloads, which keeps executions independent
With this configuration, Playwright captures download events and provides access to the Download object, which can then be used to save or validate files.
How to Automate File Downloads with Playwright (JavaScript)
Once the environment is ready, the next step is to automate how file downloads are triggered and captured in a test. In Playwright, this revolves around listening to the download event at the right time and then working with the Download object that gets created.
A common mistake is triggering the download first and then trying to capture it. This leads to missed events and unreliable tests. The correct approach is to start listening for the download before the action that triggers it.
Automating File Downloads: Step by Step
The flow involves three key steps. Start waiting for the download, trigger the action, and then work with the downloaded file.
import { test, expect } from '@playwright/test'; test('download file in Playwright', async ({ page }) => { await page.goto('https://example.com/download'); // Start waiting for download before clicking const downloadPromise = page.waitForEvent('download'); // Trigger the download await page.click('#download-button'); // Capture the download const download = await downloadPromise; // Save the file to a custom path await download.saveAs('downloads/sample.pdf'); // Validate file name expect(download.suggestedFilename()).toBe('sample.pdf'); });
What Happens in This Flow
Each step in the code maps directly to how Playwright handles downloads internally.
- Wait for download event: page.waitForEvent(‘download’) ensures the test is ready to capture the file
- Trigger download: The click action initiates the file download request
- Capture Download object: The resolved promise provides access to the Download object
- Save file: download.saveAs() moves the file from temporary storage to a defined location
- Validate file: Metadata such as file name can be verified
How to Automate File Downloads in Playwright (Python)
The approach to handling file downloads in Playwright (Python) follows the same core principle as JavaScript. The test needs to start listening for the download event before triggering the action, so the file can be captured reliably.
Playwright’s Python API provides built-in methods to wait for downloads and interact with the Download object, which allows access to file metadata and storage operations.
Automating File Downloads: Step by Step
The flow involves waiting for the download, triggering it, and then saving or validating the file.
from playwright.sync_api import sync_playwright, expect def test_download_file(): with sync_playwright() as p: browser = p.chromium.launch() context = browser.new_context(accept_downloads=True) page = context.new_page() page.goto("https://example.com/download") # Start waiting for download before triggering action with page.expect_download() as download_info: page.click("#download-button") # Capture the download download = download_info.value # Save the file to a custom path download.save_as("downloads/sample.pdf") # Validate file name assert download.suggested_filename == "sample.pdf" browser.close()
What Happens in This Flow
This sequence follows how Playwright manages downloads internally, ensuring the file is captured and accessible.
- Wait for download event: page.expect_download() sets up a listener before the action
- Trigger download: The click action initiates the file request
- Capture Download object: The context manager returns the Download object
- Save file: download.save_as() moves the file to a defined location
- Validate file: The file name or other attributes can be verified
How to Save Downloads to a Custom Location in Playwright
By default, Playwright stores downloaded files in a temporary location managed by the browser context. This works for basic scenarios, although real-world test flows often require more control over where files are stored so they can be accessed, shared, or validated later in the test.
Saving files to a custom location ensures that downloads are easier to track, persist across steps, and integrate with workflows such as reporting or CI artifacts.
1. How to Save a Download Using saveAs (JavaScript)
The most direct way to control file storage is by using the saveAs() method on the Download object.
const download = await downloadPromise; // Save to a custom directory await download.saveAs('downloads/report.pdf');
2. How to Save a Download Using save_as (Python)
In Python, the same behavior is achieved using the save_as() method.
download = download_info.value # Save to a custom directory download.save_as("downloads/report.pdf")
What to Consider When Using Custom Paths
Saving files to a custom location introduces a few practical considerations that impact reliability and maintainability.
- Ensure directory exists: Create the target folder before saving, otherwise the operation can fail
- Use relative paths: Keep paths relative to the project root so tests run consistently across environments
- Handle file naming: Use dynamic naming if multiple downloads occur in the same test to avoid overwrites
- Keep paths consistent in CI: Align directory structure with CI pipelines so downloaded files can be accessed as artifacts
For example, saving files under a /downloads folder within the project makes it easier to inspect outputs after test execution.
Verifying File Downloads in Playwright Automation
Triggering and saving a file is only part of the workflow. The real value comes from verifying that the correct file was downloaded, that it is complete, and that it matches the expected output. Without proper validation, tests may pass even when the downloaded content is incorrect.
In Playwright, verification can be done at multiple levels, starting from basic checks such as file name to deeper validation such as file content.
Validating File Name and Metadata
The simplest level of verification is to check whether the downloaded file matches the expected name.
- Check suggested file name: Use suggestedFilename() in JavaScript or suggested_filename in Python
- Match expected value: Compare the file name with what the application is supposed to generate
- Catch incorrect downloads: Helps identify cases where a wrong file is served
For example, validating that a report download returns report.pdf ensures the correct file is triggered.
Verifying File Existence and Size
After saving the file, the next step is to confirm that the file exists and has meaningful content.
- Check file presence: Ensure the file exists at the expected path
- Validate file size: Confirm that the file size is greater than zero
- Detect incomplete downloads: Small or empty files often indicate failed downloads
This level of validation ensures that the file is physically available and usable.
Validating File Content
For deeper validation, the file content can be inspected to ensure it contains the expected data.
- Read file content: Open the file using standard file handling libraries
- Match expected data: Verify specific values, text, or structure within the file
- Use format-specific checks: For example, parsing JSON, CSV, or PDF content depending on the file type
For example, a CSV download can be validated by checking if required columns and values are present.
Handling Multiple Downloads
Some test scenarios trigger multiple file downloads in a single flow. These cases require careful handling to ensure each file is validated correctly.
- Track each download event: Capture downloads individually using separate listeners
- Use unique file names: Avoid overwriting files when saving
- Validate in sequence: Ensure each file is verified against its expected output
This approach helps maintain clarity and avoids confusion when multiple files are involved.
Best Practices for Automating File Downloads in Playwright
Handling file downloads in Playwright becomes more reliable when the implementation follows a consistent structure. Small gaps in handling events, file storage, or validation can introduce flaky behavior that is difficult to debug later. These best practices focus on making download flows predictable, stable, and easy to maintain across different environments.
- Start listening before triggering downloads: Always set up the download event listener before performing the action, so the file is captured reliably without timing issues
- Enable download handling at the context level: Configure the browser context with acceptDownloads: true, so Playwright can capture and manage downloads properly
- Use explicit save locations: Save files using saveAs() or save_as() to a known directory, so they can be accessed and validated consistently
- Keep file paths environment-friendly: Use relative paths and a consistent folder structure, so tests run smoothly across local setups and CI pipelines
- Validate beyond file existence: Check file name, size, and content, so the test confirms that the correct file is downloaded and usable
- Handle multiple downloads carefully: Capture each download event separately and use unique file names, so files do not overwrite each other
- Avoid hardcoded waits: Rely on Playwright’s event-based methods instead of static delays, so tests remain stable under different execution speeds
- Clean up downloaded files when needed: Remove files after execution or manage them as test artifacts, so storage remains organized
- Log and track download steps: Add logging around download actions and validations, so failures are easier to trace and debug
Conclusion
To download files in Playwright, set up the browser context with download support and ensure the environment is correctly installed. Capture the download event before triggering actions, save files to defined locations, and verify their names, sizes, and content. Additionally, apply consistent handling for multiple downloads to maintain reliable and repeatable test automation.
Related Articles
Playwright Install Guide: Setup for Node, Python, Java & .NET
Learn how to install Playwright step by step for Node.js, Python, Java, and .NET. Verify installatio...
Playwright Architecture: Client, Server, Browsers Explained
Playwright architecture defines how tests interact with browsers through its core components. Learn ...
Master Playwright Config for Efficient Test Automation
Playwright config defines how tests run and behave. Learn how to configure browsers, devices, and pa...