---
title: Puppeteer · Cloudflare Browser Rendering docs
description: Learn how to use Puppeteer with Cloudflare Workers for browser
  automation. Access Puppeteer API, manage sessions, and optimize browser
  rendering.
lastUpdated: 2025-11-03T18:48:20.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/browser-rendering/platform/puppeteer/
  md: https://developers.cloudflare.com/browser-rendering/platform/puppeteer/index.md
---

[Puppeteer](https://pptr.dev/) is one of the most popular libraries that abstract the lower-level DevTools protocol from developers and provides a high-level API that you can use to easily instrument Chrome/Chromium and automate browsing sessions. Puppeteer is used for tasks like creating screenshots, crawling pages, and testing web applications.

Puppeteer typically connects to a local Chrome or Chromium browser using the DevTools port. Refer to the [Puppeteer API documentation on the `Puppeteer.connect()` method](https://pptr.dev/api/puppeteer.puppeteer.connect) for more information.

The Workers team forked a version of Puppeteer and patched it to connect to the Workers Browser Rendering API instead. After connecting, the developers can then use the full [Puppeteer API](https://github.com/cloudflare/puppeteer/blob/main/docs/api/index.md) as they would on a standard setup.

Our version is open sourced and can be found in [Cloudflare's fork of Puppeteer](https://github.com/cloudflare/puppeteer). The npm can be installed from [npmjs](https://www.npmjs.com/) as [@cloudflare/puppeteer](https://www.npmjs.com/package/@cloudflare/puppeteer):

* npm

  ```sh
  npm i -D @cloudflare/puppeteer
  ```

* yarn

  ```sh
  yarn add -D @cloudflare/puppeteer
  ```

* pnpm

  ```sh
  pnpm add -D @cloudflare/puppeteer
  ```

## Use Puppeteer in a Worker

Once the [browser binding](https://developers.cloudflare.com/browser-rendering/platform/wrangler/#bindings) is configured and the `@cloudflare/puppeteer` library is installed, Puppeteer can be used in a Worker:

* JavaScript

  ```js
  import puppeteer from "@cloudflare/puppeteer";


  export default {
    async fetch(request, env) {
      const browser = await puppeteer.launch(env.MYBROWSER);
      const page = await browser.newPage();
      await page.goto("https://example.com");
      const metrics = await page.metrics();
      await browser.close();
      return Response.json(metrics);
    },
  };
  ```

* TypeScript

  ```ts
  import puppeteer from "@cloudflare/puppeteer";


  interface Env {
    MYBROWSER: Fetcher;
  }


  export default {
    async fetch(request, env): Promise<Response> {
      const browser = await puppeteer.launch(env.MYBROWSER);
      const page = await browser.newPage();
      await page.goto("https://example.com");
      const metrics = await page.metrics();
      await browser.close();
      return Response.json(metrics);
    },
  } satisfies ExportedHandler<Env>;
  ```

This script [launches](https://pptr.dev/api/puppeteer.puppeteernode.launch) the `env.MYBROWSER` browser, opens a [new page](https://pptr.dev/api/puppeteer.browser.newpage), [goes to](https://pptr.dev/api/puppeteer.page.goto) <https://example.com/>, gets the page load [metrics](https://pptr.dev/api/puppeteer.page.metrics), [closes](https://pptr.dev/api/puppeteer.browser.close) the browser and prints metrics in JSON.

### Keep Alive

If users omit the `browser.close()` statement, it will stay open, ready to be connected to again and [re-used](https://developers.cloudflare.com/browser-rendering/workers-bindings/reuse-sessions/) but it will, by default, close automatically after 1 minute of inactivity. Users can optionally extend this idle time up to 10 minutes, by using the `keep_alive` option, set in milliseconds:

```js
const browser = await puppeteer.launch(env.MYBROWSER, { keep_alive: 600000 });
```

Using the above, the browser will stay open for up to 10 minutes, even if inactive.

### Set a custom user agent

To specify a custom user agent in Puppeteer, use the `page.setUserAgent()` method. This is useful if the target website serves different content based on the user agent.

```js
await page.setUserAgent(
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
);
```

Note

The `userAgent` parameter does not bypass bot protection. Requests from Browser Rendering will always be identified as a bot.

## Element selection

Puppeteer provides multiple methods for selecting elements on a page. While CSS selectors work as expected, XPath selectors are not supported due to security constraints in the Workers runtime.

Instead of using Xpath selectors, you can use CSS selectors or `page.evaluate()` to run XPath queries in the browser context:

```ts
const innerHtml = await page.evaluate(() => {
  return (
    // @ts-ignore this runs on browser context
    new XPathEvaluator()
      .createExpression("/html/body/div/h1")
      // @ts-ignore this runs on browser context
      .evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue
      .innerHTML
  );
});
```

Note

`page.evaluate()` can only return primitive types like strings, numbers, and booleans. Returning complex objects like `HTMLElement` will not work.

## Session management

In order to facilitate browser session management, we've added new methods to `puppeteer`:

### List open sessions

`puppeteer.sessions()` lists the current running sessions. It will return an output similar to this:

```json
[
  {
    "connectionId": "2a2246fa-e234-4dc1-8433-87e6cee80145",
    "connectionStartTime": 1711621704607,
    "sessionId": "478f4d7d-e943-40f6-a414-837d3736a1dc",
    "startTime": 1711621703708
  },
  {
    "sessionId": "565e05fb-4d2a-402b-869b-5b65b1381db7",
    "startTime": 1711621703808
  }
]
```

Notice that the session `478f4d7d-e943-40f6-a414-837d3736a1dc` has an active worker connection (`connectionId=2a2246fa-e234-4dc1-8433-87e6cee80145`), while session `565e05fb-4d2a-402b-869b-5b65b1381db7` is free. While a connection is active, no other workers may connect to that session.

### List recent sessions

`puppeteer.history()` lists recent sessions, both open and closed. It's useful to get a sense of your current usage.

```json
[
  {
    "closeReason": 2,
    "closeReasonText": "BrowserIdle",
    "endTime": 1711621769485,
    "sessionId": "478f4d7d-e943-40f6-a414-837d3736a1dc",
    "startTime": 1711621703708
  },
  {
    "closeReason": 1,
    "closeReasonText": "NormalClosure",
    "endTime": 1711123501771,
    "sessionId": "2be00a21-9fb6-4bb2-9861-8cd48e40e771",
    "startTime": 1711123430918
  }
]
```

Session `2be00a21-9fb6-4bb2-9861-8cd48e40e771` was closed explicitly with `browser.close()` by the client, while session `478f4d7d-e943-40f6-a414-837d3736a1dc` was closed due to reaching the maximum idle time (check [limits](https://developers.cloudflare.com/browser-rendering/platform/limits/)).

You should also be able to access this information in the dashboard, albeit with a slight delay.

### Active limits

`puppeteer.limits()` lists your active limits:

```json
{
  "activeSessions": [
    { "id": "478f4d7d-e943-40f6-a414-837d3736a1dc" },
    { "id": "565e05fb-4d2a-402b-869b-5b65b1381db7" }
  ],
  "allowedBrowserAcquisitions": 1,
  "maxConcurrentSessions": 2,
  "timeUntilNextAllowedBrowserAcquisition": 0
}
```

* `activeSessions` lists the IDs of the current open sessions
* `maxConcurrentSessions` defines how many browsers can be open at the same time
* `allowedBrowserAcquisitions` specifies if a new browser session can be opened according to the rate [limits](https://developers.cloudflare.com/browser-rendering/platform/limits/) in place
* `timeUntilNextAllowedBrowserAcquisition` defines the waiting period before a new browser can be launched.

## Puppeteer API

The full Puppeteer API can be found in the [Cloudflare's fork of Puppeteer](https://github.com/cloudflare/puppeteer/blob/main/docs/api/index.md).
