ScreenshotNeo

BlogHow-to

How to generate a PDF from a URL with Browserless

Use Browserless’s /pdf REST API to turn a URL into a paginated PDF. Learn the request options, runnable examples, limits, and fixes for common failures.

By the ScreenshotNeo team4 October 202611 min read

To generate a paginated PDF from a URL with Browserless, send an authenticated POST request to its /pdf REST endpoint. Put the page URL and optional print settings in a JSON body, provide your Browserless token in the query string, then save the response bytes as a PDF. The endpoint returns PDF data directly, not JSON.

This guide covers Browserless’s standard paginated PDF workflow, its rendering options and limitations, examples in cURL, Python, and Node.js, and how to troubleshoot common failures. For the current endpoint and parameter details, see the Browserless PDF API documentation.

1. What you need

  • A Browserless API token from your Browserless account.
  • A page that the Browserless browser can reach. It may be public or require the relevant cookies, headers, or authentication configuration.
  • A destination file or storage location for the returned binary PDF.

Use the regional endpoint shown in your Browserless account or current documentation. The examples below use https://production-sfo.browserless.io/pdf. Browserless documents /chromium/pdf as an equivalent route; /pdf is the preferred REST endpoint.

Keep the token private. It appears in the URL query string, so avoid logging full request URLs or exposing them in client-side code. For a production application, make the request from a server you control.

2. Generate a PDF with cURL

This runnable example requests an A4 PDF with print backgrounds and header/footer rendering enabled, then writes the response to result.pdf. Replace the token placeholder before running it.

curl -X POST \
  "https://production-sfo.browserless.io/pdf?token=YOUR_API_TOKEN_HERE" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/pdf' \
  -d '{
    "url": "https://example.com/",
    "options": {
      "format": "A4",
      "printBackground": true,
      "displayHeaderFooter": true
    }
  }' \
  -o result.pdf

After the request completes, open result.pdf with a PDF reader. The -o option saves the response body as bytes; without it, binary output may be printed to the terminal.

You can also send raw HTML instead of a URL by replacing the url field with html. Send one or the other, not both.

curl -X POST \
  "https://production-sfo.browserless.io/pdf?token=YOUR_API_TOKEN_HERE" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/pdf' \
  -d '{
    "html": "<!doctype html><html><body><h1>Invoice</h1><p>Example</p></body></html>",
    "options": { "format": "Letter", "printBackground": true }
  }' \
  -o invoice.pdf

3. Generate a PDF with Python

Install the HTTP client with python -m pip install requests. This example checks for an HTTP error before writing the binary response.

import requests

endpoint = "https://production-sfo.browserless.io/pdf"
params = {"token": "YOUR_API_TOKEN_HERE"}
payload = {
    "url": "https://example.com/",
    "options": {
        "format": "A4",
        "printBackground": True,
        "displayHeaderFooter": True,
        "margin": {
            "top": "20mm",
            "right": "15mm",
            "bottom": "20mm",
            "left": "15mm"
        }
    }
}

response = requests.post(
    endpoint,
    params=params,
    json=payload,
    headers={"Accept": "application/pdf"},
    timeout=90,
)
response.raise_for_status()

content_type = response.headers.get("Content-Type", "")
if "application/pdf" not in content_type:
    raise RuntimeError(f"Expected a PDF response, got {content_type!r}")

with open("result.pdf", "wb") as pdf_file:
    pdf_file.write(response.content)

print("Saved result.pdf")

The timeout is a client-side limit for waiting on the HTTP response, not a guarantee that the remote page will finish rendering in that time. Set it to suit your application and Browserless configuration.

4. Generate a PDF with Node.js

This example uses the built-in fetch API available in current Node.js releases. It reads the response as an ArrayBuffer and writes the exact bytes to disk.

import { writeFile } from "node:fs/promises";

const endpoint = "https://production-sfo.browserless.io/pdf";
const url = new URL(endpoint);
url.searchParams.set("token", process.env.BROWSERLESS_TOKEN ?? "YOUR_API_TOKEN_HERE");

const response = await fetch(url, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Accept": "application/pdf"
  },
  body: JSON.stringify({
    url: "https://example.com/",
    options: {
      format: "A4",
      printBackground: true,
      displayHeaderFooter: true,
      margin: { top: "20mm", right: "15mm", bottom: "20mm", left: "15mm" }
    }
  })
});

if (!response.ok) {
  const detail = await response.text();
  throw new Error(`Browserless returned HTTP ${response.status}: ${detail}`);
}

const contentType = response.headers.get("content-type") ?? "";
if (!contentType.includes("application/pdf")) {
  throw new Error(`Expected application/pdf, got ${contentType || "no Content-Type"}`);
}

const bytes = Buffer.from(await response.arrayBuffer());
await writeFile("result.pdf", bytes);
console.log("Saved result.pdf");

Set BROWSERLESS_TOKEN in the process environment in deployment. Do not place a real token in a browser application or commit it to source control.

5. Configure PDF rendering

Pass supported print settings inside the JSON body’s options object. The following are the main choices documented for the endpoint; check the current API reference for exact accepted values and behavior.

Option What it controls When to use it
format Standard paper size, such as A4 or Letter. Use when the output should match a known paper standard.
width, height Custom paper dimensions. Use for a fixed custom page size; confirm units and accepted syntax in the API reference.
margin Top, right, bottom, and left page margins. Set explicit margins when content is clipped or needs room for headers and footers.
landscape Switches the page orientation. Use for wide tables, charts, or layouts that do not fit portrait pages.
scale Scales printed page content. Adjust only when the layout needs to fit differently; inspect readability after scaling.
printBackground Includes background colors and images in print output. Enable when the page design depends on backgrounds; otherwise print styles may omit them.
displayHeaderFooter Enables print header and footer templates. Use when page numbers or running labels are needed; configure templates as documented.
pageRanges Selects which pages to emit. Useful for extracting a subset or splitting a large document into chunks.
preferCSSPageSize Lets CSS @page sizing take precedence over the API paper size. Use when the source document’s print stylesheet defines the intended page dimensions.
waitForFonts Waits for fonts to be ready before printing. Use when custom fonts load asynchronously and the PDF otherwise uses fallback fonts.
tagged Adds structural tags to the PDF output. Use as one accessibility aid, then validate the result for your requirements.

A page’s CSS can affect print output. In particular, @media print rules may hide or restyle elements, and @page can control sizing when CSS page sizing is preferred. Test the PDF itself rather than assuming the screen layout and printed layout are identical.

Browserless states that Chrome’s print output contains selectable text. Enabling tagged: true adds structural tags, but does not certify the PDF as PDF/UA compliant. The result depends on the source markup, so validate accessibility separately if formal compliance matters.

6. Handle dynamic pages and authentication

A URL can return its initial HTML before client-side content, images, or fonts are ready. Browserless supports navigation and waiting controls as well as cookies, HTTP authentication, extra headers, scripts, and styles. Configure only what the page needs, using the request fields and syntax in the PDF API reference.

  • For a page behind a login, provide the required authentication or session cookies through the supported request configuration.
  • For personalized pages, pass the required headers or cookies and avoid putting private values in logs.
  • For client-rendered content, choose an appropriate wait condition or delay. A page being navigated does not always mean its data has loaded.
  • For custom print behavior, supply an appropriate stylesheet or script through documented options, or use source-side @media print rules.
  • For a page that depends on a custom font, enable the font-readiness option and make sure the browser can fetch the font resource.

Waiting longer can help with slow content, but it also increases render time and may still fail if the page is stuck on an application error or never reaches the expected state.

7. Paginated PDFs, continuous pages, and document metadata

Ordinary paginated PDF

Use /pdf for the normal print layout: content flows across pages of a selected format, with margins and print settings.

One continuous page for a long webpage

The /pdf REST endpoint does not produce one single, continuous page for an entire long webpage. Browserless directs this use case to /function with custom Puppeteer code that calculates and sets the page height. That gives you control over the rendering logic, but you must implement and maintain the browser-side code yourself. See the Browserless PDF API guide.

Split a large PDF job

If a long multi-page document fails as one request, the Browserless guide recommends splitting it into pageRanges chunks and merging the resulting PDFs afterward. This can make failures easier to isolate, but requires a PDF merge step in your application.

Set Title or Author metadata

The documented /pdf route does not set common document metadata such as Title or Author during generation. Generate the PDF, then post-process it with a PDF library such as pdf-lib if those fields are required.

8. Troubleshoot common errors

Symptom Likely cause Fix
Unauthorized response The token is missing, malformed, expired, or sent in the wrong place. Pass the account token as the token query parameter and confirm the endpoint and account configuration.
Forbidden destination The target URL is not permitted by the service or its destination policy. Check the exact destination and Browserless account or endpoint rules. Do not assume every URL is reachable.
Bad request or malformed-data response The JSON is invalid, an option has the wrong shape, or both url and html were sent. Validate the JSON, use only one source field, and compare option names and types with the API reference.
Not found The route is incorrect or the request is pointed at an unavailable path. Use the documented regional /pdf endpoint and verify the URL spelling.
Timeout The page is slow, blocked, waiting on an unresolved resource, or the PDF is large. Check that the target loads, use the necessary wait control, reduce unnecessary waiting, or split the work with page ranges when appropriate.
Rate limit The request rate exceeds the service’s current allowance. Respect the response and account limits, add bounded retry with backoff for transient limits, and avoid immediately repeating requests in a tight loop.
Internal error or unavailable response The browser service or a rendering dependency failed temporarily. Retry selectively with backoff, record the status and request context without logging secrets, and alert if failures persist.
Saved file is not a PDF The client saved an error body, treated the response as JSON, or failed to preserve binary bytes. Check the HTTP status and Content-Type, then save raw response bytes in binary mode or from an ArrayBuffer.
Blank or incomplete content The page content loads after the chosen navigation point or requires authentication. Provide required cookies or headers and configure an appropriate wait condition for the page’s actual load behavior.
Missing backgrounds or unexpected layout Print CSS differs from screen CSS, background printing is off, or CSS page sizing is taking precedence. Enable printBackground when needed, inspect print styles, and review the interaction between @page and the page-size options.
Wrong fonts Font files have not loaded or are not reachable from the rendering browser. Wait for fonts to be ready and check the font resource’s availability and access requirements.
Missing Title or Author The route does not set those common PDF metadata fields. Post-process the generated PDF with a library such as pdf-lib.

Browserless documents authorization, forbidden-destination, not-found, timeout, rate-limit, internal-error, and unavailable response statuses. Treat non-success responses as errors before writing a PDF file; status codes and exact operational limits can depend on the current service configuration.

9. Performance, reliability, and cost

  • Rendering time: Each request needs page navigation, resource loading, and print rendering. Wait only for the conditions the page requires. A fixed delay that is longer than necessary slows every job; one that is too short creates incomplete PDFs.
  • Large documents: More pages and complex page content increase work. If the job fails at large size, try documented page-range chunks and merge the output.
  • Retries: Retry transient timeouts, rate limits, or service-unavailable failures with bounded exponential backoff and a maximum attempt count. Do not blindly retry malformed requests or authorization failures; correct the request first.
  • Binary handling: Check status and content type before persisting the response. This prevents an HTML or JSON error body from being mistaken for a PDF.
  • Secrets: Keep the API token server-side, redact it from logs, and avoid returning it to browsers or embedding it in public URLs.
  • Cost: The research sources for this article do not establish Browserless pricing or plan limits. Check Browserless’s current account and pricing information before estimating production cost; do not infer a per-PDF price from this API example.

For dependable workflows, record the target identifier, request duration, HTTP status, and whether the saved file begins and opens as a PDF. Avoid logging full authenticated URLs, cookies, or sensitive page contents.

10. Or skip the browser setup

If you need a PDF from a URL without building and maintaining browser-rendering code, ScreenshotNeo provides a one-call website screenshot API that also returns PDFs. Its API accepts a URL in a GET request; see the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o page.pdf

Use the PDF output option documented by ScreenshotNeo when you need a PDF response. ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, and cache hits are not billed, and response headers say which page verdict and billing status applied. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free 1,000 screenshots a month, with no card required.

11. Frequently asked questions

Does Browserless return a URL to the finished PDF?

The documented REST response is the PDF binary itself. Save the response bytes to a file or upload those bytes to your own storage if you need a shareable URL.

Can I make searchable PDFs?

Browserless says Chrome’s print output contains real selectable text. Whether the text is useful depends on the source page and its rendered content.

Does tagged: true guarantee PDF accessibility compliance?

No. It adds structural tags, but Browserless does not describe the result as certified PDF/UA output. Validate the final document against the requirements that apply to your use case.

Can I generate a PDF from HTML I already have?

Yes. Send an html field instead of url, and do not include both in the same request.

Which Browserless path should I choose for a long page?

Use /pdf for conventional paginated output. Use /function with custom Puppeteer logic when the requirement is one continuous page with a calculated height.

Sources