browser-rendering

Headless Chrome automation for web scraping, screenshots, PDFs, and testing at the edge. Load when capturing page screenshots, generating PDFs, scraping dynamic content, extracting structured data, or automating browser interactions. Supports REST API, Puppeteer, Playwright, and Stagehand.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "browser-rendering" with this command: npx skills add null-shot/cloudflare-skills/null-shot-cloudflare-skills-browser-rendering

Browser Rendering

Cloudflare Browser Rendering provides headless Chrome instances on the global edge network for web scraping, screenshots, PDF generation, and automated testing. Choose from REST API for simple tasks or Workers Bindings (Puppeteer, Playwright, Stagehand) for advanced automation.

Choosing an Integration Method

MethodUse CaseComplexity
REST APISimple screenshots, PDFs, markdown extraction, structured dataLow - just HTTP requests
PuppeteerIndustry-standard Chrome automation, porting existing scriptsMedium - familiar API
PlaywrightModern cross-browser automation, AI agent integration (MCP)Medium - developer-friendly
StagehandAI-native automation with natural language selectorsLow - resilient to site changes

REST API Method

For simple, stateless tasks like capturing screenshots or generating PDFs without writing complex scripts.

Setup

Create an API token with Browser Rendering - Edit permission in the Cloudflare dashboard.

Available Endpoints

EndpointPurpose
/contentFetch fully-rendered HTML
/screenshotCapture page screenshot
/pdfGenerate PDF document
/snapshotTake webpage snapshot
/scrapeExtract HTML elements
/jsonCapture structured data using AI
/linksRetrieve all links from page
/markdownExtract markdown content

REST API Example

curl -X POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/browser-rendering/screenshot \
  -H "Authorization: Bearer {api_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "fullPage": true,
    "type": "png"
  }' \
  --output screenshot.png

Monitoring usage: Check the X-Browser-Ms-Used header in responses to see browser time consumed (in milliseconds).

Workers Bindings Method

For complex workflows, persistent sessions, and custom automation. Requires deploying a Cloudflare Worker.

Configuration

Add browser binding to wrangler.jsonc:

{
  "name": "browser-automation",
  "main": "src/index.ts",
  "compatibility_date": "2025-09-17",
  "compatibility_flags": ["nodejs_compat"],
  "browser": {
    "binding": "BROWSER"
  }
}

Option A: Puppeteer

Industry-standard Chrome automation API, ideal for porting existing scripts.

Installation:

npm install @cloudflare/puppeteer --save-dev

Basic example:

import puppeteer from "@cloudflare/puppeteer";

interface Env {
  BROWSER: Fetcher;
}

export default {
  async fetch(request, env): Promise<Response> {
    const { searchParams } = new URL(request.url);
    const url = searchParams.get("url");

    if (!url) {
      return new Response("Missing ?url parameter", { status: 400 });
    }

    const browser = await puppeteer.launch(env.BROWSER);
    try {
      const page = await browser.newPage();
      await page.goto(url);
      const text = await page.$eval("body", (el) => el.textContent);

      return Response.json({ bodyText: text });
    } finally {
      await browser.close();
    }
  },
} satisfies ExportedHandler<Env>;

Option B: Playwright (Recommended for New Projects)

Modern browser automation with developer-friendly API and AI agent integration.

Installation:

npm install @cloudflare/playwright --save-dev

Current version: v1.57.0

Basic example:

import { launch } from "@cloudflare/playwright";

interface Env {
  BROWSER: Fetcher;
}

export default {
  async fetch(request, env): Promise<Response> {
    const browser = await launch(env.BROWSER);
    try {
      const page = await browser.newPage();
      await page.goto("https://example.com");
      
      const title = await page.title();
      const screenshot = await page.screenshot({ type: "png" });

      return new Response(screenshot, {
        headers: { "Content-Type": "image/png" },
      });
    } finally {
      await browser.close();
    }
  },
} satisfies ExportedHandler<Env>;

Playwright advantages:

  • Built-in test assertions with expect() from @cloudflare/playwright/test
  • Trace files for debugging (downloadable trace.zip)
  • Storage state for persisting cookies/localStorage
  • MCP integration for AI agents

Option C: Stagehand (AI-Native)

Uses natural language selectors instead of brittle CSS selectors, making automation resilient to website changes.

Example:

// Instead of: await page.click("#submit-button")
// Use natural language: await page.act("click the submit button")

Stagehand is ideal for AI agents that need to autonomously navigate websites without breaking when the DOM structure changes.

FIRST: Installation (Workers Bindings)

Choose your library and install:

# Puppeteer (industry standard)
npm install @cloudflare/puppeteer --save-dev

# OR Playwright (modern, recommended)
npm install @cloudflare/playwright --save-dev

# OR Stagehand (AI-native)
npm install @cloudflare/stagehand --save-dev

When to Use Browser Rendering

Use CaseRecommended MethodWhy
Simple screenshotsREST APINo code required, just HTTP request
PDF generationREST API or PuppeteerREST for simple, Puppeteer for custom headers/auth
Web scrapingPuppeteer or PlaywrightFull DOM access, complex navigation
Automated testingPlaywrightBuilt-in assertions, trace files
SEO analysisREST API /markdown or /jsonAI-powered structured extraction
AI agentsPlaywright (MCP) or StagehandNatural language automation, resilient selectors
Page monitoringREST API or PuppeteerREST for periodic checks, Puppeteer for complex flows

Quick Reference

OperationAPI
Launch browserawait puppeteer.launch(env.BROWSER_RENDERING)
Create new pageawait browser.newPage()
Navigate to URLawait page.goto(url)
Get HTML contentawait page.content()
Extract textawait page.$eval("selector", el => el.textContent)
Take screenshotawait page.screenshot({ type: "png" })
Generate PDFawait page.pdf({ format: "A4" })
Close browserawait browser.close()

Basic Page Scraping

import puppeteer from "@cloudflare/puppeteer";

interface Env {
  BROWSER_RENDERING: Fetcher;
}

export default {
  async fetch(request, env): Promise<Response> {
    const { searchParams } = new URL(request.url);
    let url = searchParams.get("url");

    if (url) {
      url = new URL(url).toString(); // normalize
      const browser = await puppeteer.launch(env.BROWSER_RENDERING);
      const page = await browser.newPage();
      await page.goto(url);
      
      // Parse the page content
      const content = await page.content();
      
      // Find text within the page content
      const text = await page.$eval("body", (el) => el.textContent);
      
      // Do something with the text
      // e.g. log it to the console, write it to KV, or store it in a database.
      console.log(text);

      // Ensure we close the browser session
      await browser.close();

      return Response.json({
        bodyText: text,
      });
    } else {
      return Response.json({
        error: "Please add an ?url=https://example.com/ parameter"
      }, { status: 400 });
    }
  },
} satisfies ExportedHandler<Env>;

Screenshot Capture

Capture screenshots of web pages as PNG or JPEG:

import puppeteer from "@cloudflare/puppeteer";

interface Env {
  BROWSER_RENDERING: Fetcher;
}

export default {
  async fetch(request, env): Promise<Response> {
    const { searchParams } = new URL(request.url);
    const url = searchParams.get("url");

    if (!url) {
      return new Response("Missing ?url parameter", { status: 400 });
    }

    const browser = await puppeteer.launch(env.BROWSER_RENDERING);
    try {
      const page = await browser.newPage();
      
      // Set viewport size
      await page.setViewport({ width: 1920, height: 1080 });
      
      await page.goto(url, { waitUntil: "networkidle0" });
      
      // Capture screenshot
      const screenshot = await page.screenshot({
        type: "png",
        fullPage: true, // Capture entire page
      });

      return new Response(screenshot, {
        headers: { "Content-Type": "image/png" },
      });
    } finally {
      await browser.close();
    }
  },
} satisfies ExportedHandler<Env>;

PDF Generation

Convert web pages to PDF documents:

import puppeteer from "@cloudflare/puppeteer";

interface Env {
  BROWSER_RENDERING: Fetcher;
}

export default {
  async fetch(request, env): Promise<Response> {
    const { searchParams } = new URL(request.url);
    const url = searchParams.get("url");

    if (!url) {
      return new Response("Missing ?url parameter", { status: 400 });
    }

    const browser = await puppeteer.launch(env.BROWSER_RENDERING);
    try {
      const page = await browser.newPage();
      await page.goto(url, { waitUntil: "networkidle0" });
      
      // Generate PDF
      const pdf = await page.pdf({
        format: "A4",
        printBackground: true,
        margin: {
          top: "20px",
          right: "20px",
          bottom: "20px",
          left: "20px",
        },
      });

      return new Response(pdf, {
        headers: { "Content-Type": "application/pdf" },
      });
    } finally {
      await browser.close();
    }
  },
} satisfies ExportedHandler<Env>;

Browser Lifecycle Management

CRITICAL: Always close the browser after use to prevent memory leaks and ensure resources are freed:

const browser = await puppeteer.launch(env.BROWSER_RENDERING);
try {
  const page = await browser.newPage();
  // ... perform operations
} finally {
  // Always close, even if an error occurs
  await browser.close();
}

Best practices:

  1. Use try/finally to ensure cleanup
  2. Close browser even if operations fail
  3. Each request should launch and close its own browser
  4. Don't reuse browser instances across requests
  5. Set reasonable timeouts to prevent hanging

DOM Manipulation and Extraction

Extract structured data from pages:

const browser = await puppeteer.launch(env.BROWSER_RENDERING);
try {
  const page = await browser.newPage();
  await page.goto(url);
  
  // Extract multiple elements
  const data = await page.evaluate(() => {
    return {
      title: document.querySelector("h1")?.textContent,
      links: Array.from(document.querySelectorAll("a")).map(a => ({
        text: a.textContent,
        href: a.href,
      })),
      images: Array.from(document.querySelectorAll("img")).map(img => img.src),
    };
  });

  return Response.json(data);
} finally {
  await browser.close();
}

Wait Strategies

Wait for content to load before scraping:

const page = await browser.newPage();
await page.goto(url);

// Wait for specific selector
await page.waitForSelector(".content-loaded");

// Wait for navigation with options
await page.goto(url, {
  waitUntil: "networkidle0", // Wait until network is idle
  timeout: 30000, // 30 second timeout
});

// Wait for custom condition
await page.waitForFunction(() => {
  return document.querySelector(".dynamic-content") !== null;
});

Error Handling

Handle common browser automation errors:

const browser = await puppeteer.launch(env.BROWSER_RENDERING);
try {
  const page = await browser.newPage();
  
  // Set timeout for navigation
  await page.goto(url, { timeout: 30000 });
  
} catch (error) {
  if (error.name === "TimeoutError") {
    return new Response("Page load timeout", { status: 504 });
  }
  
  console.error("Browser error:", error);
  return new Response("Browser automation failed", { status: 500 });
  
} finally {
  await browser.close();
}

Puppeteer vs Playwright

FeaturePuppeteerPlaywright
API StyleChrome DevTools ProtocolHigher-level abstractions
Test AssertionsManualBuilt-in expect()
DebuggingConsole logsTrace files with GUI
Storage PersistenceManualBuilt-in storage state API
MCP IntegrationNoYes (for AI agents)

Choose Puppeteer if: You have existing scripts or prefer Chrome DevTools Protocol.

Choose Playwright if: Starting new, need test assertions, want better debugging, or building AI agents.

See references/puppeteer.md for complete Playwright-specific features including test assertions, trace files, and storage state patterns

Detailed References

Best Practices

General

  1. Choose the right method: REST API for simple tasks, Workers Bindings for complex automation
  2. Always close browsers: Use try/finally to ensure browser.close() is called (Workers Bindings only)
  3. Monitor usage: Check X-Browser-Ms-Used header (REST) or dashboard for browser time consumed
  4. Set timeouts: Prevent hanging requests with reasonable timeout values
  5. Handle errors gracefully: Catch TimeoutError and 429 rate limit errors
  6. Test locally first: Use wrangler dev to iterate before deploying

Workers Bindings Specific

  1. Reuse sessions: Keep browsers open with keep_alive option (up to 10 minutes) for better performance
  2. Use waitUntil options: Wait for appropriate page state (networkidle0, load, domcontentloaded)
  3. Consider caching: Cache static screenshots/PDFs in R2 or KV
  4. Respect robots.txt: Check site policies before automated scraping
  5. Check session history: Use playwright.history() or puppeteer.history() to debug idle timeouts

REST API Specific

  1. Spread requests evenly: Rate limits are per-second, not burst (e.g., 6/min = 1 per 10 seconds)
  2. Handle 429 responses: Read Retry-After header and retry appropriately
  3. Use AI endpoints: /json and /markdown endpoints use AI for structured extraction

Common Patterns

See references/patterns.md for complete examples including:

  • Session reuse and keep-alive for performance
  • Authentication with custom headers
  • Custom user agents
  • Caching screenshots in R2
  • Rate limiting with Durable Objects

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

building-ai-agent-on-cloudflare

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

workflows

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

agents-sdk

No summary provided by upstream source.

Repository SourceNeeds Review