Save and retrieve files downloaded during browser sessions
Hyperbrowser makes it easy to download files during your browser sessions. The files you download get stored securely in our cloud infrastructure as a zip file. You can then retrieve them using a simple API call.
Self-Hosted Hyperbrowser: For some instances of self-hosted Hyperbrowser, downloads will be available at /tmp/<sessionId>/downloads on the host machine.
import { chromium } from "playwright-core";import { Hyperbrowser } from "@hyperbrowser/sdk";import { config } from "dotenv";config();const client = new Hyperbrowser({ apiKey: process.env.HYPERBROWSER_API_KEY,});async function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms));}async function waitForDownload(sessionId, timeout = 15_000) { const maxRetries = timeout / 1000; let retries = 0; while (retries < maxRetries) { console.log( `Waiting for download zip to be ready... (${retries + 1}/${maxRetries})` ); const downloadsResponse = await client.sessions.getDownloadsURL(sessionId); if ( downloadsResponse.status === "completed" || downloadsResponse.status === "failed" ) { return downloadsResponse; } await sleep(1000); retries++; } throw new Error(`Download zip not ready after ${timeout}ms`);}async function main() { const session = await client.sessions.create({ saveDownloads: true, }); console.log("Session created:", session.id); try { const browser = await chromium.connectOverCDP(session.wsEndpoint); const defaultContext = browser.contexts()[0]; const page = defaultContext.pages()[0]; const cdp = await browser.newBrowserCDPSession(); await cdp.send("Browser.setDownloadBehavior", { behavior: "allow", downloadPath: "/tmp/downloads", eventsEnabled: true, }); await page.goto("https://browser-tests-alpha.vercel.app/api/download-test"); // Download file from the page const downloadPromise = page.waitForEvent("download"); await page.getByRole("link", { name: "Download File" }).click(); const download = await downloadPromise; // Wait for the download to complete await download.path(); console.log("Downloaded file:", download.suggestedFilename()); await client.sessions.stop(session.id); await sleep(3000); // Wait for the zipped downloads to be uploaded to our storage const downloadsResponse = await waitForDownload(session.id); console.log("downloadsResponse", downloadsResponse); } catch (err) { console.error(`Encountered error: ${err}`); } finally { await client.sessions.stop(session.id); }}main().catch(console.error);
Copy
Ask AI
import { connect } from "puppeteer-core";import { Hyperbrowser } from "@hyperbrowser/sdk";import { config } from "dotenv";config();const client = new Hyperbrowser({ apiKey: process.env.HYPERBROWSER_API_KEY,});async function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms));}async function waitForDownload(sessionId, timeout = 15_000) { const maxRetries = timeout / 1000; let retries = 0; while (retries < maxRetries) { console.log( `Waiting for download zip to be ready... (${retries + 1}/${maxRetries})` ); const downloadsResponse = await client.sessions.getDownloadsURL(sessionId); if ( downloadsResponse.status === "completed" || downloadsResponse.status === "failed" ) { return downloadsResponse; } await sleep(1000); retries++; } throw new Error(`Download zip not ready after ${timeout}ms`);}async function main() { const session = await client.sessions.create({ saveDownloads: true, }); console.log("Session created:", session.id); try { const browser = await connect({ browserWSEndpoint: session.wsEndpoint, defaultViewport: null, }); const defaultContext = browser.defaultBrowserContext(); const page = (await defaultContext.pages())[0]; const cdp = await browser.target().createCDPSession(); await cdp.send("Browser.setDownloadBehavior", { behavior: "allow", downloadPath: "/tmp/downloads", eventsEnabled: true, }); await page.goto("https://browser-tests-alpha.vercel.app/api/download-test"); // Download file from the page // Set up download listener cdp.on("Browser.downloadWillBegin", (event) => { console.log("Download started:", event.suggestedFilename); }); // Create a promise that resolves when the download is complete const downloadPromise = new Promise((resolve) => { cdp.on("Browser.downloadProgress", (event) => { if (event.state === "completed" || event.state === "canceled") { resolve("Done"); } }); }); // Start the download and wait for it to complete await Promise.all([downloadPromise, page.locator("#download").click()]); await client.sessions.stop(session.id); await sleep(3000); // Wait for the zipped downloads to be uploaded to our storage const downloadsResponse = await waitForDownload(session.id); console.log("downloadsResponse", downloadsResponse); } catch (err) { console.error(`Encountered error: ${err}`); } finally { await client.sessions.stop(session.id); }}main().catch(console.error);
The downloads zip is synced in real-time to files that are downloaded during the session so you can retrieve it before the session stops as well.
By default, most PDF urls opened in the browser will open in a PDF viewer in the browser rather being downloaded. To force all PDFs to be downloaded, enable the enableAlwaysOpenPdfExternally/enable_always_open_pdf_externally parameter when creating the session.
Similarly as above, you can get the downloads zip of files that were downloaded during the session used by an AI Agent. We just need to create a session with saveDownloads set to true and then pass in that session ID. Here is an example of doing it with OpenAI CUA.
Copy
Ask AI
import { Hyperbrowser } from "@hyperbrowser/sdk";import { config } from "dotenv";config();const client = new Hyperbrowser({ apiKey: process.env.HYPERBROWSER_API_KEY,});async function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms));}async function waitForDownload(sessionId, timeout = 15_000) { const maxRetries = timeout / 1000; let retries = 0; while (retries < maxRetries) { console.log( `Waiting for download zip to be ready... (${retries + 1}/${maxRetries})` ); const downloadsResponse = await client.sessions.getDownloadsURL(sessionId); if ( downloadsResponse.status === "completed" || downloadsResponse.status === "failed" ) { return downloadsResponse; } await sleep(1000); retries++; } throw new Error(`Download zip not ready after ${timeout}ms`);}async function main() { const session = await client.sessions.create({ saveDownloads: true, }); console.log("Session created:", session.id); try { const resp = await client.agents.cua.startAndWait({ task: "1. Go to this site https://browser-tests-alpha.vercel.app/api/download-test. 2. Click on the Download File link once, then end the task. Do not wait or double check the download, just end the task.", sessionId: session.id, }); console.log("Status:", resp.status); console.log("Final result:", resp.data?.finalResult); await sleep(3000); // Wait for the zipped downloads to be uploaded to our storage const downloadsResponse = await waitForDownload(session.id); console.log("downloadsResponse", downloadsResponse); } catch (err) { console.error(`Encountered error: ${err}`); } finally { await client.sessions.stop(session.id); }}main().catch(console.error);
Check out the Agents Docs for more information on how to use AI Agents with Hyperbrowser.