Skip to main content
Unlike screenshots saved locally, files downloaded during browser automation are stored in Browserbase’s cloud storage. Retrieve them using the Browserbase API. A common use case for headless browsers is downloading files from web pages. Browserbase syncs every downloaded file to cloud storage and appends a Unix timestamp to avoid naming conflicts (e.g., sample.pdf becomes sample-1719265797164.pdf).
View or run the example template here

Triggering downloads

First, trigger a download in your browser automation:
  1. Create a browser session and get the session ID
  2. Connect to the session using your preferred framework
  3. Configure your library’s downloads location
  4. Perform the download action in your automation script
import { chromium } from "playwright-core";
import { Browserbase } from "@browserbasehq/sdk";

(async () => {
  const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY! });
  const session = await bb.sessions.create();

  const browser = await chromium.connectOverCDP(session.connectUrl);
  const defaultContext = browser.contexts()[0];
  const page = defaultContext.pages()[0];

  // Required to avoid playwright overriding location
  const client = await defaultContext.newCDPSession(page);
  await client.send("Browser.setDownloadBehavior", {
    behavior: "allow",
    downloadPath: "downloads",
    eventsEnabled: true,
  });

  await page.goto("https://browser-tests-alpha.vercel.app/api/download-test");

  const [download] = await Promise.all([
    page.waitForEvent("download"),
    page.locator("#download").click(),
  ]);

  let downloadError = await download.failure();
  if (downloadError !== null) {
    console.log("Error happened on download:", downloadError);
    throw new Error(downloadError);
  }

  // Store the session ID to retrieve downloads later
  console.log("Download completed. Session ID:", session.id);

  await page.close();
  await browser.close();
})().catch((error) => console.error(error.message));
Critical: setDownloadBehavior ConfigurationWhen using Playwright or Puppeteer, you must call Browser.setDownloadBehavior via CDP to ensure downloads are synced to Browserbase’s storage. Pay special attention to the downloadPath parameter—it must be set to "downloads" exactly as shown in the examples above.Common misconfiguration issues:
  • Using an absolute path (e.g., /tmp/downloads) instead of "downloads"
  • Omitting the setDownloadBehavior call entirely
  • Setting behavior to something other than "allow"
Without proper configuration, your downloads won’t be available for retrieval.
Opening a PDF URL in a browser session also triggers a download to Browserbase’s cloud storage. To view the PDF instead of downloading it, configure your browser settings as shown here.

Retrieving downloaded files

After triggering downloads, retrieve them using the Session Downloads API. The API returns files as a ZIP archive.
Files sync in real time — large downloads may not be immediately available through the /downloads endpoint. The code below includes retry logic to handle this.
Node
import { writeFileSync } from "node:fs";
import { Browserbase } from "@browserbasehq/sdk";

const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY! });

async function saveDownloadsOnDisk(sessionId: string, retryForSeconds: number) {
  return new Promise<void>((resolve, reject) => {
    let pooler: any;
    const timeout = setTimeout(() => {
      if (pooler) {
        clearInterval(pooler);
      }
    }, retryForSeconds);

    async function fetchDownloads() {
      try {
        const response = await bb.sessions.downloads.list(sessionId);
        const downloadBuffer = await response.arrayBuffer();

        if (downloadBuffer.byteLength > 22) {
          writeFileSync("downloads.zip", Buffer.from(downloadBuffer));
          clearInterval(pooler);
          clearTimeout(timeout);
          resolve();
        }
      } catch (e) {
        clearInterval(pooler);
        clearTimeout(timeout);
        reject(e);
      }
    }
    pooler = setInterval(fetchDownloads, 2000);
  });
}

(async () => {
  // Use the session ID from your browser automation to retrieve downloads
  const sessionId = "your-session-id";
  await saveDownloadsOnDisk(sessionId, 20000); // wait up to 20s
  console.log("Downloaded files are in downloads.zip");
})().catch(error => {
  console.error('Download failed:', error);
});

Session downloads API

Learn more about the available params and response fields