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

For uploads, Puppeteer can put a local file into a page’s <input type="file">, or accept a file chooser after you register to wait for it and trigger it. For downloads, Puppeteer can configure Chrome’s download policy and destination, but its current Files guide says it does not manage downloaded files programmatically. Your Node.js script must handle waiting for a saved file and checking it separately.

Upload a file through a file input

When the page exposes a standard file input, locate it and call uploadFile(). It accepts one or more paths. The example below assumes Node.js and a local file named report.pdf in the project directory:

const puppeteer = require('puppeteer');
const path = require('node:path');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com/upload');

    const fileInput = await page.waitForSelector('input[type="file"]');
    await fileInput.uploadFile(path.resolve('report.pdf'));

    // Continue with the page's submit or confirmation action.
    await page.locator('button[type="submit"]').click();
  } finally {
    await browser.close();
  }
})();

Replace the example URL, selector, file path and submit action with the page’s actual values. For multiple files, pass multiple paths: await fileInput.uploadFile(path.resolve('one.pdf'), path.resolve('two.pdf'));. The page input must allow multiple files for the site to accept them as a group.

Use a path the browser environment can access

With a locally launched browser, a relative path is resolved from the Node.js process’s current working directory; using path.resolve() makes that location explicit. If your script connects to remote Chrome, the path must be absolute and accessible to the browser environment, not merely to the machine running the script.

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.

Upload through a file chooser

Some pages reveal or click a control that opens the browser’s file chooser instead of exposing an input you can conveniently target. Register waitForFileChooser() before clicking that control; otherwise the chooser can open before Puppeteer starts waiting.

const puppeteer = require('puppeteer');
const path = require('node:path');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com/upload');

    const chooserPromise = page.waitForFileChooser();
    await page.locator('button.open-file-picker').click();
    const chooser = await chooserPromise;
    await chooser.accept([path.resolve('report.pdf')]);

    // Continue with the page's submit or confirmation action.
  } finally {
    await browser.close();
  }
})();

accept() does not check whether the supplied paths exist. Check the path yourself if needed, and use an absolute path for a remote browser. Only one browser file chooser can be open at a time; accept or cancel it before waiting for another. In headful mode, when Puppeteer is waiting for the chooser, the native picker does not appear for a person to operate.

Picker API limitation

waitForFileChooser() intercepts the browser file chooser associated with the page action; it does not intercept DOM calls such as window.showOpenFilePicker(). Do not assume this approach covers every modern file-picker interface.

Configure Chrome downloads without mistaking it for file handling

Puppeteer’s current Files guide states: “Currently, Puppeteer does not offer a way to handle file downloads in a programmatic way.” The download behavior API sets browser policy and, where required, a destination. It does not by itself tell your script that a file is complete, inspect its contents, validate it, or return its contents.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Policy Effect
deny Block browser downloads.
allow Allow downloads; requires downloadPath.
allowAndName Allow downloads and name files using download GUIDs; requires downloadPath.
default Use the browser’s default download behavior.

For a Chrome browser in Node.js, the documented connection option can configure behavior for the context:

const browser = await puppeteer.connect({
  browserWSEndpoint: process.env.CHROME_WS_ENDPOINT,
  downloadBehavior: {
    policy: 'allow',
    downloadPath: '/absolute/path/to/downloads'
  }
});

Set downloadPath to the actual destination directory. The API marks downloadBehavior with puppeteer.connect() as experimental and specifically documents this option for Chrome in Node.js. Verify the installed Puppeteer and Chrome versions before relying on it in production.

What your surrounding script still needs

After triggering the download, your application needs its own strategy to determine when the file is ready, enforce a timeout, inspect or consume the resulting file, and clean up temporary files. Those responsibilities are separate from setting the browser’s download policy. Do not treat the policy option as a download-completion signal or as a file-content API.

Choose the right Puppeteer environment

  • puppeteer: Installation downloads a compatible Chrome build by default, which is convenient for a local workflow.
  • puppeteer-core: Does not download Chrome and is intended for remote or user-managed browsers. Ensure the browser and file paths are available in the environment where Chrome runs.
  • Download configuration: The documented downloadBehavior option is Chrome/Node.js-specific; its use through puppeteer.connect() is experimental.

The official documentation pages surfaced different current version labels: the Files guide showed Puppeteer 25.12.0, while FileChooser references showed 25.9.0 and 25.10.0. API details can vary by installed version, so use the reference matching your package when signatures or behavior matter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot upload and download problems

  • “No file” or an incorrect file is uploaded: Resolve the path from the script’s working directory and confirm that it exists. For remote Chrome, use a path accessible to that remote environment.
  • The chooser wait hangs: Start waitForFileChooser() before the click that opens the chooser, and confirm the clicked control actually opens a browser chooser.
  • A later chooser does not appear: Only one chooser can be active. Accept or cancel the current one before waiting for the next.
  • The page uses showOpenFilePicker(): The documented chooser interception does not support this DOM API. This approach is not a universal solution for every picker.
  • A download is missing or goes to an unexpected place: Confirm that the selected policy allows downloads and that downloadPath is set for allow or allowAndName. Check Chrome/Node.js compatibility and the connected browser context.
  • The script reads a partial download: Download policy configuration is not a completion signal. Add a separate wait, timeout and validation strategy before consuming the file.

Or skip the browser setup

If your goal is a page capture rather than automating an upload or download flow, ScreenshotNeo is a website screenshot API and MCP server. Its API returns an image or PDF from one GET request; its documented options include cookies, custom headers and JavaScript. It is not a replacement for Puppeteer file upload or download automation.

Example cURL request (see the ScreenshotNeo API documentation):

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo removes cookie banners, newsletter popups and chat widgets before capture; bot checks, blank pages and failed loads are not billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Learn more at ScreenshotNeo, or sign up for 1,000 free screenshots a month with no card.

Frequently Asked Questions

Does Puppeteer support selecting a file in a native picker by hand?

In headful mode, the native picker does not show while Puppeteer is waiting for the chooser; provide the file path through Puppeteer instead.

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.

Can I use Puppeteer’s download behavior option with Firefox?

The documented option is specifically for Chrome in Node.js.

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.