For AI agents: a documentation index is available at /llms.txt
Skip to main content

Smart Scrape API

Intelligently scrape any URL using cascading strategies that automatically escalate from fast HTTP fetching to headless browsers and captcha solving as needed. Specify output formats to receive HTML, markdown, screenshots, PDFs, or extracted links, all in a single request.

Endpoint

  • Method: POST
  • Path: /smart-scrape
  • Auth: token query parameter (?token=)
  • Content-Type: application/json
  • Response: application/json
Prerequisites

Quickstart

curl --request POST \
--url 'https://production-sfo.browserless.io/smart-scrape?token=YOUR_API_TOKEN_HERE' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://news.ycombinator.com/",
"formats": ["html", "markdown", "links"]
}'

Response

{
"ok": true,
"statusCode": 200,
"content": "<html lang=\"en\" op=\"news\"><head><meta name=\"referrer\" content=\"origin\">...</html>",
"contentType": "text/html; charset=utf-8",
"headers": {
"content-type": "text/html; charset=utf-8",
"cache-control": "private; max-age=0"
},
"strategy": "http-fetch",
"attempted": ["http-fetch"],
"message": null,
"screenshot": null,
"pdf": null,
"markdown": "# Hacker News\n\n[new](newest) | [past](front) | [comments](newcomments) | [ask](ask) | [show](show) | [jobs](jobs) | [submit](submit)\n\n1. [Motorola GrapheneOS devices will be bootloader unlockable/relockable](https://grapheneos.social/...)...",
"links": [
"https://news.ycombinator.com/news",
"https://news.ycombinator.com/newest",
"https://news.ycombinator.com/front"
]
}

How it works

The Smart Scrape API uses a cascading strategy pipeline to fetch content in the most efficient way possible. It starts with the fastest, cheapest approach and automatically escalates to heavier strategies only when needed:

  1. Fast HTTP fetch: Makes a lightweight HTTP request that mimics a real browser's network fingerprint. This handles the majority of static and server-rendered sites in under 2 seconds.

  2. Proxied HTTP fetch: If the initial request is blocked (e.g., by IP detection), the same request is retried through the selected proxy network (residential by default, or datacenter if proxy: "datacenter" is set in the request body).

  3. Headless browser: If the page requires JavaScript rendering (single-page apps, client-rendered content), a full stealth browser is launched to render the page.

  4. Browser + captcha solving: If a captcha or bot detection challenge is encountered, the browser automatically detects and solves it (supports reCAPTCHA, Cloudflare Turnstile, and others).

The pipeline stops as soon as a strategy succeeds. The strategy field in the response tells you which approach was used, and the attempted array shows the full sequence of strategies tried.

Captcha handling scope

Smart Scrape only solves captchas that gate access to the page itself — for example, a Cloudflare Turnstile interstitial or a reCAPTCHA that blocks the page from loading. In these cases the browser solves the challenge automatically so the underlying content can be returned.

Captchas that are embedded in a form on the page (e.g., a reCAPTCHA next to a "Submit" button on a contact or signup form) are not solved. Smart Scrape fetches and returns the rendered page but does not fill, interact with, or submit forms, so form-submission captchas are left untouched in the returned HTML. If you need to submit a form behind a captcha, use BrowserQL with the solve mutation instead.

Request body

FieldTypeRequiredDefaultDescription
urlstringYes-The URL to scrape. Must be http:// or https://.
formatsstring[]No["html"]Output formats to include. Options: "html", "markdown", "screenshot", "pdf", "links".
proxystringNo"residential"Proxy network to route the scrape through: "residential" (6 units/MB) or "datacenter" (2 units/MB).

Output formats

The formats array controls what data is returned. The content field contains raw HTML for webpages, parsed JSON for API endpoints, or extracted plain text for PDF targets. Additional formats populate their respective response fields.

Markdown

Converts the page content to clean markdown, stripping scripts, styles, and non-visible elements.

JSON body:

{
"url": "https://news.ycombinator.com/",
"formats": ["markdown"]
}

cURL:

curl -s -X POST "https://production-sfo.browserless.io/smart-scrape?token=YOUR_API_TOKEN_HERE" -H "Content-Type: application/json" -d '{"url":"https://news.ycombinator.com/","formats":["markdown"]}'

Response:

{
"ok": true,
"statusCode": 200,
"content": "<!DOCTYPE html><html>...</html>",
"markdown": "# Hacker News\n\n[new](newest) | [past](front) | [comments](newcomments)...",
"screenshot": null,
"pdf": null,
"links": null,
"strategy": "http-fetch",
"attempted": ["http-fetch"],
"message": null
}

Screenshot

Returns a full-page screenshot as a base64-encoded PNG string. Including "screenshot" in formats forces a headless browser to be used.

JSON body:

{
"url": "https://news.ycombinator.com/",
"formats": ["screenshot"]
}

cURL:

curl -s -X POST "https://production-sfo.browserless.io/smart-scrape?token=YOUR_API_TOKEN_HERE" -H "Content-Type: application/json" -d '{"url":"https://news.ycombinator.com/","formats":["screenshot"]}'

Response:

{
"ok": true,
"statusCode": 200,
"content": "<!DOCTYPE html><html>...</html>",
"screenshot": "iVBORw0KGgoAAAANSUhEUgAA...",
"pdf": null,
"markdown": null,
"links": null,
"strategy": "browser",
"attempted": ["browser"],
"message": null
}

PDF

Returns the page as a base64-encoded PDF string. Like "screenshot", including "pdf" forces a headless browser.

JSON body:

{
"url": "https://news.ycombinator.com/",
"formats": ["pdf"]
}

cURL:

curl -s -X POST "https://production-sfo.browserless.io/smart-scrape?token=YOUR_API_TOKEN_HERE" -H "Content-Type: application/json" -d '{"url":"https://news.ycombinator.com/","formats":["pdf"]}'

Response:

{
"ok": true,
"statusCode": 200,
"content": "<!DOCTYPE html><html>...</html>",
"pdf": "JVBERi0xLjQKMSAwIG9iago8PA...",
"screenshot": null,
"markdown": null,
"links": null,
"strategy": "browser",
"attempted": ["browser"],
"message": null
}

Extracts all links (<a href>) from the page, resolves relative URLs to absolute, and filters to http:// and https:// links only.

JSON body:

{
"url": "https://news.ycombinator.com/",
"formats": ["links"]
}

cURL:

curl -s -X POST "https://production-sfo.browserless.io/smart-scrape?token=YOUR_API_TOKEN_HERE" -H "Content-Type: application/json" -d '{"url":"https://news.ycombinator.com/","formats":["links"]}'

Response:

{
"ok": true,
"statusCode": 200,
"content": "<!DOCTYPE html><html>...</html>",
"links": [
"https://news.ycombinator.com/news",
"https://news.ycombinator.com/newest",
"https://news.ycombinator.com/front",
"https://grapheneos.social/@GrapheneOS/116160393783585567"
],
"screenshot": null,
"pdf": null,
"markdown": null,
"strategy": "http-fetch",
"attempted": ["http-fetch"],
"message": null
}

PDF targets

A PDF target is a URL that points directly to an existing PDF. This is different from requesting the "pdf" output format above, which renders a webpage as a new PDF.

Smart Scrape recognizes a PDF when the response uses Content-Type: application/pdf. For responses with a missing content type or application/octet-stream, the final URL path must end in .pdf. The body must also begin with the %PDF- signature. Recognized PDFs handled by the http-fetch and http-proxy strategies have their plain text extracted into content. When "markdown" is requested, markdown contains the extracted text with pages separated by blank lines. Because Smart Scrape does not extract links from inside PDFs, links is null for PDF targets.

Password-protected PDFs, corrupt PDFs, PDFs larger than 25 MiB, PDFs over 10,000 pages, and PDFs whose extracted text exceeds 25 MiB return ok: false with an explanatory message. Requests that force a browser strategy remain unchanged and do not use PDF-target parsing. This includes requests for "screenshot" or "pdf" output and requests using a profile.

Response fields

The response examples above are abbreviated. Every response includes all 12 fields listed below.

FieldTypeDescription
okbooleanWhether the scrape succeeded.
statusCodenumber | nullThe HTTP status code from the target site, or null on network errors.
contentstring | object | nullPage content as an HTML string, extracted PDF text, or a parsed JSON object if the target returns application/json. null on failure.
contentTypestring | nullThe content type of the scraped page.
headersobjectHTTP response headers from the target site.
strategystringThe strategy that produced the result (or was being attempted on failure).
attemptedstring[]All strategies attempted, in order.
messagestring | nullError message on failure, null on success.
screenshotstring | nullBase64-encoded PNG screenshot, when "screenshot" is in formats.
pdfstring | nullBase64-encoded PDF, when "pdf" is in formats.
markdownstring | nullMarkdown conversion of a webpage, or page-separated extracted text for a PDF target, when "markdown" is in formats.
linksstring[] | nullExtracted links, when "links" is in formats. Always null for PDF targets.

JSON auto-parsing

When the target URL returns JSON content (e.g., an API endpoint with Content-Type: application/json), the content field will contain the parsed JSON object rather than a raw string:

{
"ok": true,
"statusCode": 200,
"content": {
"userId": 1,
"id": 1,
"title": "Example post title",
"body": "Example post body..."
},
"contentType": "application/json; charset=utf-8",
"strategy": "http-fetch",
"attempted": ["http-fetch"],
"message": null
}

Error handling

On failure, the response still returns HTTP 200 with ok: false and a message describing the error:

{
"ok": false,
"statusCode": null,
"content": null,
"contentType": null,
"headers": {},
"strategy": "browser-captcha",
"attempted": ["http-fetch", "http-proxy", "browser", "browser-captcha"],
"message": "Captcha was detected but could not be solved",
"screenshot": null,
"pdf": null,
"markdown": null,
"links": null
}

Using a profile

Scrape authenticated pages by passing a saved profile via the ?profile= query parameter. The browser loads the profile's cookies, localStorage, and IndexedDB before navigating, so the page is accessed as the logged-in user.

curl --request POST \
--url 'https://production-sfo.browserless.io/smart-scrape?token=YOUR_API_TOKEN_HERE&profile=acme-prod' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://app.example.com/dashboard",
"formats": ["html", "markdown"]
}'
tip

Create and manage profiles via the Authenticated Profiles workflow. The profile name is scoped to your API token — other tokens cannot access your profiles.

Configuration options

The /smart-scrape API supports a timeout query parameter to control the maximum time allowed for the scrape operation:

POST /smart-scrape?token=YOUR_API_TOKEN_HERE&timeout=30000

The timeout value is in milliseconds and applies to each strategy attempt. If not specified, the server default timeout is used.

FAQ & Troubleshooting

What is the Browserless Smart Scrape API?

Smart Scrape uses a cascading strategy: it tries a fast HTTP fetch first and only launches a full browser if the initial request fails or returns incomplete content. This reduces cost and latency on pages that don't need a full browser.

When should I use Smart Scrape vs the /content API?

Use Smart Scrape when you want automatic fallback from HTTP to browser rendering. Use /content when you know the page requires JavaScript rendering and want to skip the initial HTTP attempt.

Does Smart Scrape handle bot-protected pages?

Yes. When the HTTP fetch is blocked, Smart Scrape falls back to a full browser with stealth capabilities. You can also enable proxies for additional protection.

Next steps

Was this page helpful?