Content API
Fetch fully rendered HTML from a real browser, including JavaScript-rendered content. Send a url to navigate, or html to render inline content.
Endpoint
- Method:
POST - Path:
/content - Auth:
tokenquery parameter (?token=) - Content-Type:
application/json - Response:
text/html
See the OpenAPI reference for complete details.
- A Browserless API token from your account dashboard
Quickstart
- cURL
- JavaScript
- Python
curl -X POST \
"https://production-sfo.browserless.io/content?token=YOUR_API_TOKEN_HERE" \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/"
}'
const TOKEN = "YOUR_API_TOKEN_HERE";
const url = `https://production-sfo.browserless.io/content?token=${TOKEN}`;
const headers = {
"Cache-Control": "no-cache",
"Content-Type": "application/json"
};
const data = {
url: "https://example.com/"
};
const fetchContent = async () => {
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const content = await response.text();
console.log(content);
};
fetchContent();
import requests
TOKEN = "YOUR_API_TOKEN_HERE"
url = f"https://production-sfo.browserless.io/content?token={TOKEN}"
headers = {
"Cache-Control": "no-cache",
"Content-Type": "application/json"
}
data = {
"url": "https://example.com/"
}
response = requests.post(url, headers=headers, json=data)
print(response.text)
Response
The API returns the fully rendered HTML content as text/html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example Domain</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body{
background:#eee;
width:60vw;
margin:15vh auto;
font-family:system-ui,sans-serif
}
h1{font-size:1.5em}
div{opacity:0.8}
a:link,a:visited{color:#348}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in documentation examples without needing permission. Avoid use in operations.</p>
<p><a href="https://iana.org/domains/example">Learn more</a></p>
</div>
</body>
</html>
Bot detection troubleshooting
If you're hitting Cloudflare challenges, "HeadlessChrome" blocks, or CAPTCHA pages, work up this ladder one step at a time. Each step adds cost or setup, so stop at the first one that gets you through. Every step also pays normal browser time (1 unit per 30 seconds).
| Step | What to try | Extra cost |
|---|---|---|
| 1 | Add stealth=true to the request. See launch parameters. | None |
| 2 | Switch to the /unblock API with proxy=residential. | 6 units per MB of residential proxy traffic |
| 3 | Connect over Browsers as a Service (BaaS) with solveCaptchas=true to solve CAPTCHAs that still appear. | 10 units per successful solve |
| 4 | Use BrowserQL's solve mutation for full control over when and how challenges are solved. | 10 units per successful solve |
stealth=true alone often isn't enough for Cloudflare. If you still get a challenge with it on, move to step 2 rather than retrying. Failed solve attempts aren't charged. See unit consumption for the full cost breakdown, Bypass CAPTCHAs for the end-to-end approach, and Solving Cloudflare challenges for working code.
If content is empty or incomplete, the site may be blocking automation. Signs include:
- Empty HTML response or minimal content
- Partial page content missing key elements
- Different content compared to a regular browser
- Blocked requests or access denied messages
The /unblock API is specifically designed to bypass bot detection mechanisms like Datadome and passive CAPTCHAs. It can return HTML content directly when content: true is set and works best with residential proxies.
Configuration options
The /content API supports shared request configuration options that apply across REST endpoints:
- Waiting for things: Wait for events, functions, selectors, or timeouts before returning content
- Navigation options: Customize navigation behavior with
gotoOptions - Rejecting undesired requests: Block resources with
rejectResourceTypesandrejectRequestPattern - Continue on error: Use
bestAttemptto continue when async events fail or time out
FAQ & Troubleshooting
Why am I getting a 401 Unauthorized error?
Your API token is missing or invalid. Include it as a ?token= query parameter or in the Authorization header. Verify the token in your account dashboard.
My request returns an empty response
The page may not have finished loading. Increase waitForTimeout or use waitForSelector to wait for specific content before extracting data.