Getting Started with Browserless: Cloud Headless Browser Testing
Browserless is a managed headless Chrome service. Instead of spinning up Chrome yourself — dealing with dependencies, sandbox flags, memory leaks, and process management — you point your code at a WebSocket endpoint or REST API and let Browserless handle the browser lifecycle.
The core value proposition: your test or scraping code stays the same. The browser runs somewhere else.
What Browserless Actually Is
Browserless runs Chromium (and Chrome) in a containerized environment and exposes two interfaces:
- WebSocket endpoint — drop-in replacement for
puppeteer.launch()orplaywright.chromium.launch(). Your existing automation code connects to a remote browser instead of a local one. - REST API — fire-and-forget endpoints for common tasks: screenshots, PDFs, content extraction, scraping. No Puppeteer/Playwright required for simple cases.
The hosted version is at browserless.io. The self-hosted version is a Docker image you run anywhere.
Hosted vs Self-Hosted
Hosted (browserless.io)
You get an API key and a WebSocket URL like wss://chrome.browserless.io?token=YOUR_API_KEY. No infrastructure to manage. Pricing is based on concurrent sessions and monthly usage. Good for teams that don't want to maintain browser infrastructure.
Self-hosted
Pull the Docker image, configure environment variables, run it. You control concurrency limits, memory, timeouts, and data residency. No per-request cost beyond your hosting. The image is ghcr.io/browserless/chromium (v2+) or browserless/chrome (v1).
The self-hosted path makes sense if you have high volume, strict data requirements, or want to run inside a private network alongside your test infrastructure.
REST API Overview
The REST API handles one-off tasks without requiring a persistent WebSocket connection. All endpoints accept a JSON body describing what to do.
/screenshot
Capture a PNG or JPEG of any URL.
curl -X POST \
"https://chrome.browserless.io/screenshot?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"options": {
"fullPage": true,
"type": "png"
}
}' \
--output screenshot.png/pdf
Generate a PDF from a URL or raw HTML.
curl -X POST \
"https://chrome.browserless.io/pdf?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"options": {
"printBackground": true,
"format": "A4"
}
}' \
--output page.pdf/content
Fetch the fully-rendered HTML of a page after JavaScript execution. Useful when you need the DOM after React/Vue/Angular has run.
curl -X POST \
"https://chrome.browserless.io/content?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}' /scrape
Extract structured data from a page without writing full Puppeteer code. You pass CSS selectors and get back the matching elements.
curl -X POST \
"https://chrome.browserless.io/scrape?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://news.ycombinator.com",
"elements": [
{ "selector": ".titleline a" }
]
}'Response:
{
"data": [
{
"selector": ".titleline a",
"results": [
{ "text": "Show HN: ...", "href": "https://..." },
...
]
}
]
}/function
Execute arbitrary JavaScript in a browser context. You send a function body as a string; Browserless runs it and returns the result.
curl -X POST \
"https://chrome.browserless.io/function?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"code": "module.exports = async ({ page }) => { await page.goto(\"https://example.com\"); return page.title(); }"
}'WebSocket Endpoint for Puppeteer/Playwright
The WebSocket interface is the primary way to run full automation scripts. The endpoint is:
wss://chrome.browserless.io?token=YOUR_TOKENFor self-hosted: ws://localhost:3000
Both Puppeteer and Playwright support connecting to an existing browser over WebSocket instead of launching a new process. This is covered in detail in the Puppeteer and Playwright integration posts in this series, but the short version:
Puppeteer:
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://chrome.browserless.io?token=YOUR_TOKEN'
});Playwright:
const browser = await chromium.connectOverCDP(
'wss://chrome.browserless.io?token=YOUR_TOKEN'
);Once connected, the API is identical to a locally launched browser.
Your First REST API Request
Here's a complete Node.js example that takes a screenshot without Puppeteer or Playwright — just fetch:
const fs = require('fs');
const TOKEN = process.env.BROWSERLESS_TOKEN;
async function screenshot(url, outputPath) {
const response = await fetch(
`https://chrome.browserless.io/screenshot?token=${TOKEN}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url,
options: {
fullPage: true,
type: 'png'
}
})
}
);
if (!response.ok) {
const text = await response.text();
throw new Error(`Browserless error: ${response.status} — ${text}`);
}
const buffer = await response.arrayBuffer();
fs.writeFileSync(outputPath, Buffer.from(buffer));
console.log(`Screenshot saved to ${outputPath}`);
}
screenshot('https://example.com', 'output.png');No Chrome install required. No apt-get install chromium-browser. No sandbox flags. It just works.
What to Check Before Committing
A few things to verify before building on Browserless:
- Token security: Never hardcode your API token. Use environment variables.
- Timeout defaults: The default request timeout is 30 seconds. Long-running scripts need
?timeout=60000in the query string. - Concurrent session limits: The hosted free tier limits concurrent sessions. If you're running parallel tests, check your plan or self-host with your own limits.
- Version pinning: Self-hosted, pin the Docker image tag.
browserless/chrome:latestwill drift and break your tests.
Next Steps
The REST API is the fastest way to get started, but the real power comes from running full Puppeteer and Playwright test suites against a remote browser. The rest of this series covers:
- Setting up self-hosted Browserless with Docker
- Connecting Playwright to Browserless
- Connecting Puppeteer to Browserless
- Scaling concurrent headless tests in CI