/download API
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.
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 thecode
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
}
}''