Back to Articles

Running Playwright in Cloudflare Workers: Browser Automation at the Edge

[ View on GitHub ]

Running Playwright in Cloudflare Workers: Browser Automation at the Edge

Hook

Browser automation has always required spinning up heavyweight processes on servers. What if you could run Playwright tests and scrapers from 300+ edge locations worldwide, with no infrastructure to manage?

Context

Traditional browser automation lives in an uncomfortable middle ground. Tools like Playwright and Puppeteer are incredibly powerful, but they demand resources that don't mesh well with modern serverless architectures. You can't just spawn a Chrome process in AWS Lambda without jumping through hoops—cold starts are brutal, execution time limits are punishing, and scaling is expensive.

Cloudflare saw an opportunity. They already run one of the world's largest edge networks, and with their Browser Rendering API, they provision browser instances across their infrastructure. But there was a mismatch: developers love Playwright's ergonomic API, yet it was built assuming Node.js would launch local browser processes. Cloudflare's fork bridges this gap, maintaining Playwright's developer experience while completely replacing the browser connection layer to work with remote browsers over the Chrome DevTools Protocol. It's Playwright's API surface running on infrastructure you don't manage, deployed to the edge.

Technical Insight

The architectural challenge here is fascinating. Standard Playwright uses its own protocol to communicate with browsers it spawns as child processes. Cloudflare's fork rips out this assumption entirely. Instead of process management, it connects to pre-provisioned browser instances via CDP (Chrome DevTools Protocol) over WebSocket connections managed by Cloudflare's Browser Rendering service.

Here's what a basic implementation looks like:

import playwright from '@cloudflare/playwright';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const browser = await playwright.chromium.connectOverCDP(
      env.BROWSER_RENDERING_ENDPOINT
    );
    
    const page = await browser.newPage();
    await page.goto('https://example.com');
    
    const title = await page.title();
    const screenshot = await page.screenshot();
    
    await browser.close();
    
    return new Response(screenshot, {
      headers: { 
        'content-type': 'image/png',
        'x-page-title': title 
      }
    });
  }
};

Notice the connectOverCDP method—this is where the magic happens. Instead of playwright.chromium.launch(), you're connecting to a browser that Cloudflare manages. The environment binding BROWSER_RENDERING_ENDPOINT is automatically populated by Workers with credentials and connection details.

The fork maintains compatibility with Playwright 1.58.2's API surface, which means most of your existing Playwright knowledge transfers directly. You can use locators, assertions, network interception, and even advanced features like tracing:

const context = await browser.newContext();
await context.tracing.start({ screenshots: true, snapshots: true });

const page = await context.newPage();
await page.goto('https://complex-spa.example.com');
await page.locator('button[data-testid="submit"]').click();

const tracingBuffer = await context.tracing.stop();
// Store or return the trace for debugging

Under the hood, the fork had to solve the Workers runtime constraints. Workers don't have a traditional filesystem, so any file operations are redirected to /tmp, which is ephemeral. The fork also leverages the nodejs_compat compatibility flag, which enables a subset of Node.js APIs within the V8 isolate runtime. This is crucial because Playwright's codebase assumes certain Node.js primitives exist.

The recent migration to standard CDP protocol (version 1.3.0+) is significant. Earlier versions used a proprietary protocol, but switching to CDP opens the door to better upstream compatibility and feature parity. CDP is what Chrome DevTools uses to communicate with browsers, so it's a stable, well-documented protocol. This means features landing in Chromium are more likely to work immediately without fork-specific modifications.

One clever aspect is how the fork handles sessions and contexts. In traditional Playwright, creating a new browser context is cheap because it's just a new profile in the same process. Here, contexts still map to CDP targets, maintaining isolation while reusing the same remote browser connection. This keeps the familiar API while optimizing for the remote execution model.

Gotcha

The Browser Rendering service only provides Chromium. If your test suite relies on cross-browser testing with Firefox or WebKit, you're out of luck. This isn't a limitation of the fork—it's inherent to what Cloudflare offers. For many use cases (scraping, screenshots, SPA testing), Chromium-only is fine. But if browser compatibility is your mandate, you'll need to run standard Playwright elsewhere.

Playwright Test, the full-featured test runner, is mostly unsupported. You get the assertion library (expect), which is useful, but the test orchestration, parallelization, fixtures, and reporting features don't work. This makes sense given Workers' execution model—you're running in response to HTTP requests, not orchestrating a local test suite. If you want to use this fork for actual testing, you'll need to build your own test runner that calls Workers endpoints or manages test execution externally. The fork is better suited for production browser automation tasks (scraping, PDF generation, screenshot services) than replacing your entire CI/CD testing infrastructure. Video recording is also completely unavailable, and file system operations beyond /tmp will fail silently or throw errors.

Verdict

Use if: You're already invested in Cloudflare Workers and need browser automation for scraping, screenshot generation, or end-to-end checks that run at the edge. The global distribution and serverless scaling make this compelling for user-facing automation (like generating social media preview images on-demand) or distributed monitoring. Also use if you want Playwright's API specifically—its locator strategies and modern async patterns are superior to Puppeteer's older design.

Skip if: You need multi-browser testing, video recording, or the full Playwright Test framework. Also skip if you're not already on Cloudflare Workers—the standard Playwright library offers more features and flexibility in traditional Node.js environments, and you won't benefit from edge deployment if your infrastructure is elsewhere. Finally, skip if your automation needs heavy file I/O or long-running sessions that exceed Workers' execution limits.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/automation/cloudflare-playwright.svg)](https://starlog.is/api/badge-click/automation/cloudflare-playwright)