Get started (46)·续
Create a new Worker project named browser-worker by running:
npmyarnpnpm
npm create cloudflare@latest -- browser-worker
yarn create cloudflare browser-worker
pnpm create cloudflare@latest browser-worker
For setup, select the following options:
- For What would you like to start with?, choose
Hello World example. - For Which template would you like to use?, choose
Worker only. - For Which language do you want to use?, choose
JavaScript / TypeScript. - For Do you want to use git for version control?, choose
Yes. - For Do you want to add an AGENTS.md file to help AI coding tools understand Cloudflare APIs?, choose
Yes. - For Do you want to deploy your application?, choose
No(we will be making some changes before deploying).
2. Install Puppeteer
In your browser-worker directory, install Cloudflare’s fork of Puppeteer:
npmyarnpnpmbun
npm i -D @cloudflare/puppeteer
yarn add -D @cloudflare/puppeteer
pnpm add -D @cloudflare/puppeteer
bun add -d @cloudflare/puppeteer
3. Create a KV namespace
Browser Run can be used with other developer products. You might need a relational database, an R2 bucket to archive your crawled pages and assets, a Durable Object to keep your browser instance alive and share it with multiple requests, or Queues to handle your jobs asynchronously.
For the purpose of this example, we will use a KV store to cache your screenshots.
Create two namespaces, one for production and one for development.
npx wrangler kv namespace create BROWSER_KV_DEMO
npx wrangler kv namespace create BROWSER_KV_DEMO --preview
Take note of the IDs for the next step.
4. Configure the Wrangler configuration file
Configure your browser-worker project's Wrangler configuration file by adding a browser binding and a Node.js compatibility flag. Bindings allow your Workers to interact with resources on the Cloudflare developer platform. Your browser binding name is set by you, this guide uses the name MYBROWSER. Browser bindings allow for communication between a Worker and a headless browser which allows you to do actions such as taking a screenshot, generating a PDF, and more.
Update your Wrangler configuration file with the Browser Run API binding and the KV namespaces you created:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "browser-worker",
"main": "src/index.js",
"upload_source_maps": true,
// Set this to today's date
"compatibility_date": "2026-10-27",
"compatibility_flags": ["nodejs_compat"],
"browser": {
"binding": "MYBROWSER"
},
"kv_namespaces": [
{
"binding": "BROWSER_KV_DEMO",
"id": "22cf855786094a88a6906f8edac425cd",
"preview_id": "e1f8b68b68d24381b57071445f96e623"
}
]
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "browser-worker"
main = "src/index.js"
upload_source_maps = true
# Set this to today's date
compatibility_date = "2026-10-27"
compatibility_flags = [ "nodejs_compat" ]
[browser]
binding = "MYBROWSER"
[[kv_namespaces]]
binding = "BROWSER_KV_DEMO"
id = "22cf855786094a88a6906f8edac425cd"
preview_id = "e1f8b68b68d24381b57071445f96e623"
5. Code
Update src/index.js with your Worker code:
import puppeteer from "@cloudflare/puppeteer";
export default {
async fetch(request, env) {
const { searchParams } = new URL(request.url);
let url = searchParams.get("url");
let img;
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();
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=https://example.com/ parameter");
}
},
};
Update src/index.ts with your Worker code:
import puppeteer from "@cloudflare/puppeteer";
interface Env {
MYBROWSER: Fetcher;
BROWSER_KV_DEMO: KVNamespace;
}
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=https://example.com/ parameter");
}
},
} satisfies ExportedHandler<Env>;
This Worker instantiates a browser using Puppeteer, opens a new page, navigates to the location of the 'url' parameter, takes a screenshot of the page, stores the screenshot in KV, closes the browser, and responds with the JPEG image of the screenshot.
If your Worker is running in production, it will store the screenshot to the production KV namespace. If you are running wrangler dev, it will store the screenshot to the dev KV namespace.
If the same url is requested again, it will use the cached version in KV instead, unless it expired.
6. Test
Run npx wrangler dev to test your Worker locally.
Use real headless browser during local development
To interact with a real headless browser during local development, set "remote" : true in the Browser binding configuration. Learn more in our remote bindings documentation.
To test taking your first screenshot, go to the following URL:
<LOCAL_HOST_URL>/?url=https://example.com
7. Deploy
Run npx wrangler deploy to deploy your Worker to the Cloudflare global network.
To take your first screenshot, go to the following URL:
<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/?url=https://example.com
Next steps
- Check out all the Quick Actions endpoints
- Try out the Playwright MCP
- Connect from any environment using CDP
- Learn more about Browser Run limits and pricing
If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the Cloudflare Developers community on Discord ↗︎.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"WebPage","@id":"https://developers.cloudflare.com/browser-run/get-started/#page","headline":"Get started","description":"Choose an integration method and set up your first Browser Run project using Quick Actions, Puppeteer, or Playwright.","url":"https://developers.cloudflare.com/browser-run/get-started/","inLanguage":"en","image":"https://developers.cloudflare.com/browser-run/get-started/og.png?v=dd8170fd00373d46","dateModified":"2026-10-15","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Use Browser Run Quick Actions HTTP endpoints to capture screenshots, extract HTML, generate PDFs, and perform other common browser tasks. title: Quick Actions image: https://developers.cloudflare.com/browser-run/quick-actions/og.png?v=b1c1413af4139157
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/browser-run/llms.txt
Use this file to discover all available pages before exploring further.
Docs