Cloudflare Browser Rendering

Updated on Dmytro Krasun 6 min read
Cloudflare recently launched a new Browser Rendering platform. I decided to dive into it and quickly check if I could use it in ScreenshotOne to provide a faster and better customer experience.

A short answer is not, I won’t use it now for ScreenshotOne. Maybe later, once it has fewer limitations and will be synchronized with the latest version of Puppeteer.

If you are curious about more details, please, read further. I will share what is Cloudflare’s Browser Rendering, its limitations, and its capabilities.

What is Cloudflare Browser Rendering

Cloudflare’s Browser Rendering API allows developers to programmatically control and interact with a headless browser instance running on Cloudflare’s global network. That sounds great, but don’t hurry up, there is a caveat.

The key features of Cloudflare’s Browser Rendering API include:

  1. Integration with the popular Puppeteer library, which provides a high-level API for automating browser interactions.
  2. And support for session management, allowing developers to reuse the same browser instance across multiple requests.

This enables the creation of automation flows and workflows that can perform actions such as taking screenshots of web pages, generating PDFs, gathering performance metrics, and more. And all of that on top of the Cloudflare infrastructure.

Cloudflare’s Puppeteer library

Cloudflare forked Puppeteer to minimize the size of the library for Cloudflare Workers since library space is at a premium in workers’ projects.

While they try to support as much of the existing Puppeteer core library as possible, it will be always a fork that needs to keep up with the changes in the original Puppeteer library.

A GitHub issue example

And Puppeteer’s release cadency is really good, now. Also, partially, that problem is solvable if they introduce only minimal changes to make library use as seamless as possible for workers and yet be able to quickly synchronize with the source code.

But again, Cloudflare can introduce changes that you might not expect and if you use Puppeteer extensively and with a lot of modifications, you need to keep your hand on the pulse of their fork and always check the differences.

Currently, the code will be familiar to those who work a lot with Puppeteer:

import puppeteer from "@cloudflare/puppeteer";
interface Env {
export default {
async fetch(request, env): Promise<Response> {
const { searchParams } = new URL(request.url);
let url = searchParams.get("url");
let img: Buffer;
if (url) {
url = new URL(url).toString(); // normalize
img = await env.BROWSER_KV_DEMO.get(url, { type: "arrayBuffer" });
if (img === null) {
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
await page.goto(url);
img = (await page.screenshot()) as Buffer;
await env.BROWSER_KV_DEMO.put(url, img, {
expirationTtl: 60 * 60 * 24,
await browser.close();
return new Response(img, {
headers: {
"content-type": "image/jpeg",
} else {
return new Response(
"Please add an ?url= parameter"
} satisfies ExportedHandler<Env>;


At the moment of writing this post, they have the following limits:

  • Two new browsers per minute per account.
  • Two concurrent browsers per account.
  • By default, a browser instance gets killed if it does not get any devtools command for 60 seconds, freeing one instance. Users can optionally increase this by using the keep_alive option.

ScreenshotOne runs hundreds of browsers simultaneously and these requirements make it absolutely impossible to use Cloudflare Browser Rendering for ScreenshotOne.

Frankly, I don’t know what kind of real-time applications these limitations might fit. But if you use queues and render pages asynchronously, then you probably can make something pragmatic out of it.

For screenshots, it matters even more, because the full browser is locked by Puppeteer when you render a screenshot.

It is a pity. Since you would love to use it for performance and capitalize on top of Cloudflare’s global network. But since it is very limited, now. All benefits of the performance are neglected.

Also, there are some questions: can you use proxies, can you patch the browser and load your extensions, and many more? However, these are often required for advanced automation.


I also encountered issues, it was rendering full-page screenshots when I didn’t ask it. Or it was rendering partial screenshots.

But I guess, it doesn’t matter much for you, if you your goal is to use it for scraping also.


And probably, the most important thing—Cloudflare Browser Rendering pricing structure. Cloudflare stated that the idea was to make browser rendering affordable. And they recently shared the pricing structure:

The Cloudflare Browser Rendering pricing structure

You pay based on two usage metrics:

  1. Number of sessions: A Browser Session is a new instance of a browser being launched
  2. Number of concurrent sessions: Concurrent Sessions is the number of browser instances open at once.

Utilizing Durable Objects to maintain browser sessions enhances performance by reducing the time required to initiate new sessions. Also, by reusing sessions, it decreases the need for multiple concurrent sessions.

Cloudflare strongly recommends adopting this session reuse model for applications developed on the Browser Rendering API, especially if you anticipate steady traffic.

I rendered four screenshots without any optimizations and reusing sessions:


It would cost me $0.4 for four screenshots, meaning if I rendered 2,000 screenshots, it would cost me $200, compared to $17 per 2,000 in ScreenshotOne. This calculation does not include optimizations. Additionally, I haven’t considered concurrent requests, which would significantly increase the cost, especially if the screenshots need to be rendered simultaneously.

I haven’t tried it yet, but, if can you keep one session for a whole month, it means, you will pay only $0.1. Also, you can open many pages from one browser and use it concurrently for scrapping. But for screenshots, it is still will be a problem, you can’t render screenshots in parallel with one browser instance. You will need more concurrent sessions.


Headless browser space is booming!

We need more data, more scrapping, more screenshots, and more automation. And I am surprised, frankly, that Cloudflare decided to jump into this hype train. Since I thought it was a small market size for them.

I am happy that there is such an opportunity and once it is more stable and compatible with the latest version of Puppeteer, I will consider giving it a try as a backup option for ScreenshotOne rendering.

But it must not be expensive, since I try to keep my API prices affordable. It must be performant and without concurrency limitations since I often need to render hundreds of screenshots per minute and launch hundreds of browser instances.

I will keep following their updates and see what they are up to.

As always, thanks for reading!