This site is not affiliated with or endorsed by Cloudflare, Inc. It showcases deployable experiments across most Cloudflare products.
Browser Rendering

PDF API

Generate PDFs from any webpage with Cloudflare Browser Rendering - HTML/URL to PDF API at the edge

Generate a PDF from any URL using Browser Rendering and Puppeteer's page.pdf() API.

API Reference

GET /pdf

Renders the specified URL in a headless browser and returns a PDF document.

Prop

Type

Example Request

curl "https://your-worker.workers.dev/pdf?url=https://www.cloudflare.com" \
  --output page.pdf

Success Response

Returns a PDF file with the following headers:

Content-Type: application/pdf
Cache-Control: public, max-age=60

Error Response

{
  "error": "Missing or invalid query parameter: url",
  "code": "INVALID_URL"
}

Error Codes

  • 400 - Missing or invalid url parameter (not http/https)
  • 502 - PDF generation failed (PDF_ERROR)

Use Cases

  • Convert web pages to printable PDF documents
  • Archive rendered page content with styles
  • Generate invoices or reports from HTML pages
  • Learn Browser Rendering PDF generation with Workers bindings

Limitations

  • Requires Browser Rendering enabled on your Cloudflare account
  • Local development needs npx wrangler dev --remote
  • Navigation timeout; complex or infinite-scroll pages may fail
  • Fixed viewport; no PDF margin, format, or page-size options

Use in your project

Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/pdf-api.

DependenciesNoneBindingsBrowser RenderingPlatformWorkers runtime
import puppeteer from "@cloudflare/puppeteer";import type { Page } from "@cloudflare/puppeteer";import { DEFAULT_VIEWPORT, NAVIGATION_TIMEOUT_MS } from "../constants/defaults";export async function withBrowserPage<T>(  browserBinding: Fetcher,  url: string,  fn: (page: Page) => Promise<T>): Promise<T> {  let browser: Awaited<ReturnType<typeof puppeteer.launch>> | null = null;  try {    browser = await puppeteer.launch(browserBinding);    const page = await browser.newPage();    await page.setViewport(DEFAULT_VIEWPORT);    await page.goto(url, {      waitUntil: "networkidle0",      timeout: NAVIGATION_TIMEOUT_MS,    });    return await fn(page);  } finally {    if (browser) {      try {        await browser.close();      } catch {        /* ignore close errors */      }    }  }}export async function generatePdf(browserBinding: Fetcher, url: string): Promise<Uint8Array> {  return withBrowserPage(browserBinding, url, async (page) => {    const pdf = await page.pdf({ printBackground: true });    return new Uint8Array(pdf);  });}

Deployment

Click the deploy button

Deploy to Cloudflare Workers

Enable Browser Rendering

This experiment requires Browser Rendering on your Cloudflare account. See the Browser Rendering docs.

Test your deployment

curl "https://your-worker.workers.dev/pdf?url=https://www.cloudflare.com" \
  --output page.pdf

Local Development

cd apps/experiments/pdf-api
npm install
npm run dev

npm run dev uses wrangler dev --remote so a real browser instance is available. Local dev without --remote will not work.

Test locally:

curl "http://localhost:8787/pdf?url=https://www.cloudflare.com" --output test.pdf

Cloudflare Features Used

On this page