Skip to main content
Version: v2

/download API

info

Currently, Browserless V2 is available in production via two domains: production-sfo.browserless.io and production-lon.browserless.io

The /download API is used for returning files Chrome has downloaded during the execution of puppeteer code, which is ran inside context of the browser. Browserless sets up a blank page, a fresh download directory, injects your puppeteer code, and then executes it. You can load external libraries via the import syntax, and import ESM-style modules that are written for execution inside of the browser. Once your script is finished, any downloaded files from Chromium are returned back with the appropriate content-type header.

You can check the full Open API schema here.

warning

If your download request doesn't result in a file being downloaded, browserless will likely time out the function.

Basic Usage

Here's an example of downloading a file created in the browser (a CSV file):

import puppeteer from 'puppeteer';

async function run() {
const browser = await puppeteer.launch();
const page = await browser.newPage();

// Here we generate a json file and have the browser download it
await page.evaluate(() => {
const json = {
ping: "pong",
rnd: [...Array(5)].map(() => Math.random())
}
const jsonContent = `data:application/json,${JSON.stringify(json)}`;
const encodedUri = encodeURI(jsonContent);
const link = document.createElement('a');

link.setAttribute('href', encodedUri);
link.setAttribute('download', 'data.json');
document.body.appendChild(link);
return link.click();
});
}

run();

This might come as a surprise, but unfortunately in puppeteer there's no way to know if the file was downloaded, or an API to even get it. You'll have to know ahead of time where files are kept, and watch the file system for it to complete. Instead of wiring up all that code you can send browserless an HTTP request and it takes care of all the underlying file-system calls:

JS Code

export default function ({ page }){
await page.evaluate(() => {
const json = {
ping: "pong",
rnd: [...Array(5)].map(() => Math.random())
}
const jsonContent = `data:application/json,${JSON.stringify(json)}`;
const encodedUri = encodeURI(jsonContent);
const link = document.createElement("a");

link.setAttribute("href", encodedUri);
link.setAttribute("download", "data.json");
document.body.appendChild(link);
return link.click();
});
}

cURL request

curl -X POST \
https://production-sfo.browserless.io/download?token=YOUR-API-TOKEN \
-H 'Content-Type: application/javascript' \
-d 'export default function ({ page }){
await page.evaluate(() => {
const json = {
ping: "pong",
rnd: [...Array(5)].map(() => Math.random())
}
const jsonContent = `data:application/json,${JSON.stringify(json)}`;
const encodedUri = encodeURI(jsonContent);
const link = document.createElement("a");

link.setAttribute("href", encodedUri);
link.setAttribute("download", "data.json");
document.body.appendChild(link);
return link.click();
});
};'

This API is sensitive to the downloaded file and will return an appropriate Content-Type with the response.

Import libraries

Both the /function and the /download API environments use Ecmascript modules. This means you can use import syntax over HTTP. For instance, let's try leading the Fake module.

JS Code

import { faker } from 'https://esm.sh/@faker-js/faker';

export default async function ({ page }) {
const rndName = faker.person.fullName();
const rndEmail = faker.internet.email();

await page.evaluate((name, email) => {
const jsonStr = JSON.stringify({name, email});
const jsonContent = `data:application/json,${jsonStr}`;
const encodedUri = encodeURI(jsonContent);
const link = document.createElement("a");

link.setAttribute("href", encodedUri);
link.setAttribute("download", "data.json");
document.body.appendChild(link);
return link.click();
}, rndName, rndEmail);
}

cURL request

curl -X POST \
https://production-sfo.browserless.io/download?token=YOUR-API-TOKEN \
-H 'Content-Type: application/javascript' \
-d 'import { faker } from '\''https://esm.sh/@faker-js/faker'\'';

export default async function ({ page }) {
const rndName = faker.person.fullName();
const rndEmail = faker.internet.email();

await page.evaluate((name, email) => {
const jsonStr = JSON.stringify({name, email});
const jsonContent = `data:application/json,${jsonStr}`;
const encodedUri = encodeURI(jsonContent);
const link = document.createElement("a");

link.setAttribute("href", encodedUri);
link.setAttribute("download", "data.json");
document.body.appendChild(link);
return link.click();
}, rndName, rndEmail);
}'

Example response

{
"name": "Jasmine Littel",
"email": "Giovanna26@hotmail.com"
}

JSON API

You can also use the /download API sending a JSON payload. You must send an object with the following values:

  • code: String, required — custom download code.
  • context: Object, optional — value used to pass context values and arguments to the code

Example

JS Code

export default async function ({ page, context }){
await page.evaluate((context) => {
const json = {
url: context.url,
ping: "pong",
rnd: [...Array(context.arrayLen)].map(() => Math.random())
}
const jsonContent = `data:application/json,${JSON.stringify(json)}`;
const encodedUri = encodeURI(jsonContent);
const link = document.createElement("a");

link.setAttribute("href", encodedUri);
link.setAttribute("download", "data.json");
document.body.appendChild(link);
return link.click();
}, context);
}

cURL request

curl --request POST \
--url 'http://chrome-dev.browserless.io/chrome/download' \
--header 'Content-Type: application/json' \
# Minified code
--data '{
"code": "export default async function({page:t,context:a}){await t.evaluate(t=>{let a={url:t.url,ping:`pong`,rnd:[...Array(t.arrayLen)].map(()=>Math.random())},e=`data:application/json,${JSON.stringify(a)}`,n=encodeURI(e),r=document.createElement(`a`);return r.setAttribute(`href`,n),r.setAttribute(`download`,`data.json`),document.body.appendChild(r),r.click()},a)};",
"context": {
"url": "https://browserless.io/",
"arrayLen": 10
}
}''