cloudflare-browser-rendering
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare Browser Rendering - Complete Reference
Cloudflare 浏览器渲染 - 完整参考指南
Production-ready knowledge domain for building browser automation workflows with Cloudflare Browser Rendering.
Status: Production Ready ✅
Last Updated: 2026-01-21
Dependencies: cloudflare-worker-base (for Worker setup)
Latest Versions: @cloudflare/puppeteer@1.0.4, @cloudflare/playwright@1.1.0, wrangler@4.59.3
Recent Updates (2025):
- Sept 2025: Playwright v1.55 GA, Stagehand framework support (Workers AI), /links excludeExternalLinks param
- Aug 2025: Billing GA (Aug 20), /sessions endpoint in local dev, X-Browser-Ms-Used header
- July 2025: Playwright v1.54.1 + MCP v0.0.30, Playwright local dev support (wrangler@4.26.0+), Puppeteer v22.13.1 sync, /content returns title, /json custom_ai param, /screenshot viewport 1920x1080 default
- June 2025: Web Bot Auth headers auto-included
- April 2025: Playwright support launched, free tier introduced
用于在Cloudflare浏览器渲染服务上构建浏览器自动化工作流的生产级知识库。
状态:已就绪可用于生产 ✅
最后更新:2026-01-21
依赖项:cloudflare-worker-base(用于Worker配置)
最新版本:@cloudflare/puppeteer@1.0.4、@cloudflare/playwright@1.1.0、wrangler@4.59.3
2025年更新记录:
- 2025年9月:Playwright v1.55正式发布,支持Stagehand框架(Workers AI),/links接口新增excludeExternalLinks参数
- 2025年8月:计费功能正式上线(8月20日),本地开发环境支持/sessions接口,新增X-Browser-Ms-Used请求头
- 2025年7月:Playwright v1.54.1 + MCP v0.0.30,本地开发支持Playwright(需wrangler@4.26.0+),同步Puppeteer v22.13.1版本,/content接口返回页面标题,/json接口新增custom_ai参数,/screenshot接口默认视口设为1920x1080
- 2025年6月:自动包含Web Bot认证请求头
- 2025年4月:推出Playwright支持,新增免费额度
Table of Contents
目录
Quick Start (5 minutes)
快速开始(5分钟)
1. Add Browser Binding
1. 添加浏览器绑定
wrangler.jsonc:
jsonc
{
"name": "browser-worker",
"main": "src/index.ts",
"compatibility_date": "2023-03-14",
"compatibility_flags": ["nodejs_compat"],
"browser": {
"binding": "MYBROWSER"
}
}Why nodejs_compat? Browser Rendering requires Node.js APIs and polyfills.
wrangler.jsonc:
jsonc
{
"name": "browser-worker",
"main": "src/index.ts",
"compatibility_date": "2023-03-14",
"compatibility_flags": ["nodejs_compat"],
"browser": {
"binding": "MYBROWSER"
}
}为什么需要nodejs_compat? 浏览器渲染需要Node.js API和polyfill支持。
2. Install Puppeteer
2. 安装Puppeteer
bash
npm install @cloudflare/puppeteerbash
npm install @cloudflare/puppeteer3. Take Your First Screenshot
3. 捕获第一张截图
typescript
import puppeteer from "@cloudflare/puppeteer";
interface Env {
MYBROWSER: Fetcher;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { searchParams } = new URL(request.url);
const url = searchParams.get("url") || "https://example.com";
// Launch browser
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
// Navigate and capture
await page.goto(url);
const screenshot = await page.screenshot();
// Clean up
await browser.close();
return new Response(screenshot, {
headers: { "content-type": "image/png" }
});
}
};typescript
import puppeteer from "@cloudflare/puppeteer";
interface Env {
MYBROWSER: Fetcher;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { searchParams } = new URL(request.url);
const url = searchParams.get("url") || "https://example.com";
// 启动浏览器
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
// 导航并捕获截图
await page.goto(url);
const screenshot = await page.screenshot();
// 清理资源
await browser.close();
return new Response(screenshot, {
headers: { "content-type": "image/png" }
});
}
};4. Deploy
4. 部署
bash
npx wrangler deployTest at:
https://your-worker.workers.dev/?url=https://example.comCRITICAL:
- Always pass to
env.MYBROWSER(not undefined)puppeteer.launch() - Always call when done (or use
browser.close()for session reuse)browser.disconnect() - Use compatibility flag
nodejs_compat
bash
npx wrangler deploy测试地址:
https://your-worker.workers.dev/?url=https://example.com关键注意事项:
- 必须将传递给
env.MYBROWSER(不能传undefined)puppeteer.launch() - 完成操作后务必调用(或使用
browser.close()复用会话)browser.disconnect() - 启用兼容性标志
nodejs_compat
Browser Rendering Overview
浏览器渲染概述
What is Browser Rendering?
什么是浏览器渲染?
Cloudflare Browser Rendering provides headless Chromium browsers running on Cloudflare's global network. Use familiar tools like Puppeteer and Playwright to automate browser tasks:
- Screenshots - Capture visual snapshots of web pages
- PDF Generation - Convert HTML/URLs to PDFs
- Web Scraping - Extract content from dynamic websites
- Testing - Automate frontend tests
- Crawling - Navigate multi-page workflows
Cloudflare浏览器渲染服务在Cloudflare全球网络上运行无头Chromium浏览器。你可以使用熟悉的Puppeteer和Playwright工具来自动化浏览器任务:
- 截图 - 捕获网页的视觉快照
- PDF生成 - 将HTML/URL转换为PDF
- 网页爬取 - 从动态网站提取内容
- 测试 - 自动化前端测试
- 站点遍历 - 导航多页面工作流
Two Integration Methods
两种集成方式
| Method | Best For | Complexity |
|---|---|---|
| Workers Bindings | Complex automation, custom workflows, session management | Advanced |
| REST API | Simple screenshot/PDF tasks | Simple |
This skill covers Workers Bindings (the advanced method with full Puppeteer/Playwright APIs).
| 方式 | 最佳适用场景 | 复杂度 |
|---|---|---|
| Workers绑定 | 复杂自动化、自定义工作流、会话管理 | 高级 |
| REST API | 简单的截图/PDF任务 | 简单 |
本指南聚焦Workers绑定(支持完整Puppeteer/Playwright API的高级方式)。
Puppeteer vs Playwright
Puppeteer vs Playwright
| Feature | Puppeteer | Playwright |
|---|---|---|
| API Familiarity | Most popular | Growing adoption |
| Package | | |
| Session Management | ✅ Advanced APIs | ⚠️ Basic |
| Browser Support | Chromium only | Chromium only (Firefox/Safari not yet supported) |
| Best For | Screenshots, PDFs, scraping | Testing, frontend automation |
Recommendation: Use Puppeteer for most use cases. Playwright is ideal if you're already using it for testing.
| 特性 | Puppeteer | Playwright |
|---|---|---|
| API熟悉度 | 最受欢迎 | 使用率持续增长 |
| 包名 | | |
| 会话管理 | ✅ 高级API | ⚠️ 基础功能 |
| 浏览器支持 | 仅Chromium | 仅Chromium(暂不支持Firefox/Safari) |
| 最佳适用场景 | 截图、PDF生成、网页爬取 | 测试、前端自动化 |
推荐:大多数场景使用Puppeteer。如果你已在使用Playwright进行测试,那么它是理想选择。
Puppeteer API Reference
Puppeteer API参考
Core APIs (complete reference: https://pptr.dev/api/):
Global Functions:
- - Launch new browser (CRITICAL: must pass binding)
puppeteer.launch(env.MYBROWSER, options?) - - Connect to existing session
puppeteer.connect(env.MYBROWSER, sessionId) - - List running sessions
puppeteer.sessions(env.MYBROWSER) - - List recent sessions (open + closed)
puppeteer.history(env.MYBROWSER) - - Check account limits
puppeteer.limits(env.MYBROWSER)
Browser Methods:
- - Create new tab (preferred over launching new browsers)
browser.newPage() - - Get session ID for reuse
browser.sessionId() - - Terminate session
browser.close() - - Keep session alive for reuse
browser.disconnect() - - Isolated incognito context (separate cookies/cache)
browser.createBrowserContext()
Page Methods:
- - Navigate (use
page.goto(url, { waitUntil, timeout })for dynamic content)"networkidle0" - - Capture image
page.screenshot({ fullPage, type, quality, clip }) - - Generate PDF
page.pdf({ format, printBackground, margin }) - - Execute JS in browser (data extraction, XPath workaround)
page.evaluate(() => ...) - /
page.content()- Get/set HTMLpage.setContent(html) - - Wait for element
page.waitForSelector(selector) - /
page.type(selector, text)- Form interactionpage.click(selector)
Critical Patterns:
typescript
// Must pass binding
const browser = await puppeteer.launch(env.MYBROWSER); // ✅
// const browser = await puppeteer.launch(); // ❌ Error!
// Session reuse for performance
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
if (freeSessions.length > 0) {
browser = await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
}
// Keep session alive
await browser.disconnect(); // Don't close
// XPath workaround (not directly supported)
const data = await page.evaluate(() => {
return new XPathEvaluator()
.createExpression("/html/body/div/h1")
.evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)
.singleNodeValue.innerHTML;
});核心API(完整参考:https://pptr.dev/api/):
全局函数:
- - 启动新浏览器(关键:必须传递绑定)
puppeteer.launch(env.MYBROWSER, options?) - - 连接到现有会话
puppeteer.connect(env.MYBROWSER, sessionId) - - 列出运行中的会话
puppeteer.sessions(env.MYBROWSER) - - 列出最近的会话(包括已关闭的)
puppeteer.history(env.MYBROWSER) - - 检查账户限制
puppeteer.limits(env.MYBROWSER)
浏览器方法:
- - 创建新标签页(优先选择,而非启动新浏览器)
browser.newPage() - - 获取会话ID用于复用
browser.sessionId() - - 终止会话
browser.close() - - 保持会话活跃以便复用
browser.disconnect() - - 创建隔离的隐身上下文(独立的Cookie/缓存)
browser.createBrowserContext()
页面方法:
- - 导航页面(动态内容建议使用
page.goto(url, { waitUntil, timeout }))"networkidle0" - - 捕获图片
page.screenshot({ fullPage, type, quality, clip }) - - 生成PDF
page.pdf({ format, printBackground, margin }) - - 在浏览器中执行JS(数据提取、XPath替代方案)
page.evaluate(() => ...) - /
page.content()- 获取/设置HTML内容page.setContent(html) - - 等待元素加载
page.waitForSelector(selector) - /
page.type(selector, text)- 表单交互page.click(selector)
关键模式:
typescript
// 必须传递绑定
const browser = await puppeteer.launch(env.MYBROWSER); // ✅
// const browser = await puppeteer.launch(); // ❌ 错误!
// 会话复用提升性能
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
if (freeSessions.length > 0) {
browser = await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
}
// 保持会话活跃
await browser.disconnect(); // 不要关闭
// XPath替代方案(不直接支持XPath)
const data = await page.evaluate(() => {
return new XPathEvaluator()
.createExpression("/html/body/div/h1")
.evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)
.singleNodeValue.innerHTML;
});Playwright API Reference
Playwright API参考
Status: GA (Sept 2025) - Playwright v1.55, MCP v0.0.30 support, local dev support (wrangler@4.26.0+)
Installation:
bash
npm install @cloudflare/playwrightConfiguration Requirements (2025 Update):
jsonc
{
"compatibility_flags": ["nodejs_compat"],
"compatibility_date": "2025-09-15" // Required for Playwright v1.55
}Basic Usage:
typescript
import { chromium } from "@cloudflare/playwright";
const browser = await chromium.launch(env.BROWSER);
const page = await browser.newPage();
await page.goto("https://example.com");
const screenshot = await page.screenshot();
await browser.close();Puppeteer vs Playwright:
- Import: vs
puppeteerfrom "@cloudflare/playwright"{ chromium } - Session API: Puppeteer has advanced session management (sessions/history/limits), Playwright basic
- Auto-waiting: Playwright has built-in auto-waiting, Puppeteer requires manual
waitForSelector() - MCP Support: Playwright MCP v0.0.30 (July 2025), Playwright MCP server available
- Latest Version: Playwright v1.57 support (Jan 2026 update)
Recommendation: Use Puppeteer for session reuse patterns. Use Playwright if migrating existing tests or need MCP integration.
状态:正式发布(2025年9月)- 支持Playwright v1.55、MCP v0.0.30,本地开发支持(需wrangler@4.26.0+)
安装:
bash
npm install @cloudflare/playwright配置要求(2025年更新):
jsonc
{
"compatibility_flags": ["nodejs_compat"],
"compatibility_date": "2025-09-15" // Playwright v1.55必需
}基础用法:
typescript
import { chromium } from "@cloudflare/playwright";
const browser = await chromium.launch(env.BROWSER);
const page = await browser.newPage();
await page.goto("https://example.com");
const screenshot = await page.screenshot();
await browser.close();Puppeteer vs Playwright对比:
- 导入方式:vs 从"@cloudflare/playwright"导入
puppeteer{ chromium } - 会话API:Puppeteer拥有高级会话管理(sessions/history/limits),Playwright仅支持基础功能
- 自动等待:Playwright内置自动等待,Puppeteer需要手动调用
waitForSelector() - MCP支持:Playwright支持MCP v0.0.30(2025年7月),提供Playwright MCP服务器
- 最新版本:支持Playwright v1.57(2026年1月更新)
推荐:会话复用场景使用Puppeteer。如果迁移现有测试或需要MCP集成,使用Playwright。
Session Management
会话管理
Why: Launching new browsers is slow and consumes concurrency limits. Reuse sessions for faster response, lower concurrency usage, better resource utilization.
原因:启动新浏览器速度慢且会消耗并发限制。复用会话可提升响应速度、降低并发占用、优化资源利用率。
Session Reuse Pattern (Critical)
会话复用模式(关键)
typescript
async function getBrowser(env: Env): Promise<Browser> {
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
if (freeSessions.length > 0) {
try {
return await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
} catch (e) {
console.log("Failed to connect, launching new browser");
}
}
return await puppeteer.launch(env.MYBROWSER);
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const browser = await getBrowser(env);
try {
const page = await browser.newPage();
await page.goto("https://example.com");
const screenshot = await page.screenshot();
await browser.disconnect(); // ✅ Keep alive for reuse
return new Response(screenshot, {
headers: { "content-type": "image/png" }
});
} catch (error) {
await browser.close(); // ❌ Close on error
throw error;
}
}
};Key Rules:
- ✅ - Keep session alive for reuse
browser.disconnect() - ❌ - Only on errors or when truly done
browser.close() - ✅ Always handle connection failures
typescript
async function getBrowser(env: Env): Promise<Browser> {
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
if (freeSessions.length > 0) {
try {
return await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
} catch (e) {
console.log("连接失败,启动新浏览器");
}
}
return await puppeteer.launch(env.MYBROWSER);
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const browser = await getBrowser(env);
try {
const page = await browser.newPage();
await page.goto("https://example.com");
const screenshot = await page.screenshot();
await browser.disconnect(); // ✅ 保持会话活跃以便复用
return new Response(screenshot, {
headers: { "content-type": "image/png" }
});
} catch (error) {
await browser.close(); // ❌ 出错时关闭会话
throw error;
}
}
};核心规则:
- ✅ - 保持会话活跃以便复用
browser.disconnect() - ❌ - 仅在出错或确实不再使用时调用
browser.close() - ✅ 始终处理连接失败情况
Browser Contexts (Cookie/Cache Isolation)
浏览器上下文(Cookie/缓存隔离)
Use to share browser but isolate cookies/cache:
browser.createBrowserContext()typescript
const browser = await puppeteer.launch(env.MYBROWSER);
const context1 = await browser.createBrowserContext(); // User 1
const context2 = await browser.createBrowserContext(); // User 2
const page1 = await context1.newPage();
const page2 = await context2.newPage();
// Separate cookies/cache per context使用共享浏览器实例但隔离Cookie/缓存:
browser.createBrowserContext()typescript
const browser = await puppeteer.launch(env.MYBROWSER);
const context1 = await browser.createBrowserContext(); // 用户1
const context2 = await browser.createBrowserContext(); // 用户2
const page1 = await context1.newPage();
const page2 = await context2.newPage();
// 每个上下文拥有独立的Cookie/缓存Multiple Tabs Pattern
多标签页模式
❌ Bad: Launch 10 browsers for 10 URLs (wastes concurrency)
✅ Good: 1 browser, 10 tabs via +
Promise.all()browser.newPage()typescript
const browser = await puppeteer.launch(env.MYBROWSER);
const results = await Promise.all(
urls.map(async (url) => {
const page = await browser.newPage();
await page.goto(url);
const data = await page.evaluate(() => ({ title: document.title }));
await page.close();
return { url, data };
})
);
await browser.close();❌ 不良实践:为10个URL启动10个浏览器(浪费并发资源)
✅ 最佳实践:1个浏览器,通过 + 创建10个标签页
Promise.all()browser.newPage()typescript
const browser = await puppeteer.launch(env.MYBROWSER);
const results = await Promise.all(
urls.map(async (url) => {
const page = await browser.newPage();
await page.goto(url);
const data = await page.evaluate(() => ({ title: document.title }));
await page.close();
return { url, data };
})
);
await browser.close();Common Patterns
常见模式
Screenshot with KV Caching
结合KV缓存的截图
Cache screenshots to reduce browser usage and improve performance:
typescript
interface Env {
MYBROWSER: Fetcher;
CACHE: KVNamespace;
}
export default {
async fetch(request: Request, env: 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 normalizedUrl = new URL(url).toString();
// Check cache first
let screenshot = await env.CACHE.get(normalizedUrl, { type: "arrayBuffer" });
if (!screenshot) {
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
await page.goto(normalizedUrl);
screenshot = await page.screenshot();
await browser.close();
// Cache for 24 hours
await env.CACHE.put(normalizedUrl, screenshot, { expirationTtl: 60 * 60 * 24 });
}
return new Response(screenshot, { headers: { "content-type": "image/png" } });
}
};缓存截图以减少浏览器使用并提升性能:
typescript
interface Env {
MYBROWSER: Fetcher;
CACHE: KVNamespace;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { searchParams } = new URL(request.url);
const url = searchParams.get("url");
if (!url) return new Response("缺少?url参数", { status: 400 });
const normalizedUrl = new URL(url).toString();
// 先检查缓存
let screenshot = await env.CACHE.get(normalizedUrl, { type: "arrayBuffer" });
if (!screenshot) {
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
await page.goto(normalizedUrl);
screenshot = await page.screenshot();
await browser.close();
// 缓存24小时
await env.CACHE.put(normalizedUrl, screenshot, { expirationTtl: 60 * 60 * 24 });
}
return new Response(screenshot, { headers: { "content-type": "image/png" } });
}
};AI-Enhanced Scraping
AI增强型爬取
Combine Browser Rendering with Workers AI for structured data extraction:
typescript
interface Env {
MYBROWSER: Fetcher;
AI: Ai;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { searchParams } = new URL(request.url);
const url = searchParams.get("url");
// Scrape page content
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
await page.goto(url!, { waitUntil: "networkidle0" });
const bodyContent = await page.$eval("body", el => el.innerHTML);
await browser.close();
// Extract structured data with AI
const response = await env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
messages: [{
role: "user",
content: `Extract product info as JSON from this HTML. Include: name, price, description.\n\nHTML:\n${bodyContent.slice(0, 4000)}`
}]
});
return Response.json({ url, product: JSON.parse(response.response) });
}
};Other Common Patterns: PDF generation (), structured scraping (), form automation ( + ). See bundled directory.
page.pdf()page.evaluate()page.type()page.click()templates/结合浏览器渲染与Workers AI实现结构化数据提取:
typescript
interface Env {
MYBROWSER: Fetcher;
AI: Ai;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { searchParams } = new URL(request.url);
const url = searchParams.get("url");
// 爬取页面内容
const browser = await puppeteer.launch(env.MYBROWSER);
const page = await browser.newPage();
await page.goto(url!, { waitUntil: "networkidle0" });
const bodyContent = await page.$eval("body", el => el.innerHTML);
await browser.close();
// 使用AI提取结构化数据
const response = await env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
messages: [{
role: "user",
content: `从以下HTML中提取产品信息并以JSON格式返回。需包含:名称、价格、描述。\n\nHTML:\n${bodyContent.slice(0, 4000)}`
}]
});
return Response.json({ url, product: JSON.parse(response.response) });
}
};其他常见模式:PDF生成()、结构化爬取()、表单自动化( + )。详见附带的目录。
page.pdf()page.evaluate()page.type()page.click()templates/Pricing & Limits
定价与限制
Billing GA: August 20, 2025
Free Tier: 10 min/day, 3 concurrent, 3 launches/min, 60s timeout
Paid Tier: 10 hrs/month included ($0.09/hr after), 30 concurrent ($2.00/browser after), 30 launches/min, 60s-10min timeout
Concurrency Calculation: Monthly average of daily peak usage (e.g., 35 browsers avg = (35 - 30 included) × $2.00 = $10.00/mo)
Rate Limiting: Enforced with a fixed per-second fill rate (NOT burst-friendly). 30 req/min = 1 req every 2 seconds. You CANNOT send all 30 requests at once, even if quota is unused. Check before launching:
puppeteer.limits(env.MYBROWSER)typescript
const limits = await puppeteer.limits(env.MYBROWSER);
if (limits.allowedBrowserAcquisitions === 0) {
const delay = limits.timeUntilNextAllowedBrowserAcquisition || 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}计费正式启动:2025年8月20日
免费额度:每日10分钟,3个并发,每分钟3次启动,60秒超时
付费额度:每月包含10小时(超出后$0.09/小时),30个并发(超出后$2.00/浏览器/月),每分钟30次启动,超时时间60秒-10分钟
并发计算方式:每日峰值使用量的月平均值(例如:平均35个浏览器 = (35 - 30) × $2.00 = $10.00/月)
速率限制:采用固定每秒填充速率(不支持突发流量)。30次请求/分钟 = 每2秒1次请求。即使配额未用完,也不能一次性发送30个请求。启动前请检查:
puppeteer.limits(env.MYBROWSER)typescript
const limits = await puppeteer.limits(env.MYBROWSER);
if (limits.allowedBrowserAcquisitions === 0) {
const delay = limits.timeUntilNextAllowedBrowserAcquisition || 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}Known Issues Prevention
已知问题预防
This skill prevents 8 documented issues:
本指南可预防8个已记录的问题:
Issue #1: XPath Selectors Not Supported
问题#1:XPath选择器不被支持
Error: "XPath selector not supported" or selector failures
Source: https://developers.cloudflare.com/browser-rendering/faq/#why-cant-i-use-an-xpath-selector-when-using-browser-rendering-with-puppeteer
Why It Happens: XPath poses a security risk to Workers
Prevention: Use CSS selectors or with XPathEvaluator
page.evaluate()Solution:
typescript
// ❌ Don't use XPath directly (not supported)
// await page.$x('/html/body/div/h1')
// ✅ Use CSS selector
const heading = await page.$("div > h1");
// ✅ Or use XPath in page.evaluate()
const innerHtml = await page.evaluate(() => {
return new XPathEvaluator()
.createExpression("/html/body/div/h1")
.evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)
.singleNodeValue.innerHTML;
});错误信息: "XPath selector not supported" 或选择器执行失败
来源: https://developers.cloudflare.com/browser-rendering/faq/#why-cant-i-use-an-xpath-selector-when-using-browser-rendering-with-puppeteer
原因: XPath对Workers存在安全风险
预防方案: 使用CSS选择器或在中使用XPathEvaluator
page.evaluate()解决方案:
typescript
// ❌ 不要直接使用XPath(不支持)
// await page.$x('/html/body/div/h1')
// ✅ 使用CSS选择器
const heading = await page.$("div > h1");
// ✅ 或在page.evaluate()中使用XPath
const innerHtml = await page.evaluate(() => {
return new XPathEvaluator()
.createExpression("/html/body/div/h1")
.evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)
.singleNodeValue.innerHTML;
});Issue #2: Browser Binding Not Passed (Fetcher Type Confusion)
问题#2:未传递浏览器绑定(Fetcher类型混淆)
Error: "Cannot read properties of undefined (reading 'fetch')" or "RPC receiver does not implement the method 'launch'"
Source: GitHub Issue #10772, https://developers.cloudflare.com/browser-rendering/faq/#cannot-read-properties-of-undefined-reading-fetch
Why It Happens: called without browser binding, or trying to call directly. The browser binding is a Fetcher (REST API wrapper), not a browser instance.
Prevention: Always pass to or wrapper
puppeteer.launch()env.MYBROWSER.launch()env.MYBROWSERpuppeteer.launch()chromium.launch()Solution:
typescript
// ❌ Missing browser binding
const browser = await puppeteer.launch(); // Error!
// ❌ Wrong - trying to call launch() on Fetcher directly
const browser = await env.MYBROWSER.launch(); // "RPC receiver does not implement the method 'launch'"
// ✅ Pass binding to Puppeteer/Playwright wrapper
const browser = await puppeteer.launch(env.MYBROWSER);
// or for Playwright:
const browser = await chromium.launch(env.MYBROWSER);TypeScript Type Explanation:
typescript
interface Env {
MYBROWSER: Fetcher; // It's a Fetcher, not a Browser!
}错误信息: "Cannot read properties of undefined (reading 'fetch')" 或 "RPC receiver does not implement the method 'launch'"
来源: GitHub Issue #10772, https://developers.cloudflare.com/browser-rendering/faq/#cannot-read-properties-of-undefined-reading-fetch
原因: 调用时未传入浏览器绑定,或尝试直接调用。浏览器绑定是Fetcher(REST API包装器),而非浏览器实例。
预防方案: 始终将传递给或包装函数
puppeteer.launch()env.MYBROWSER.launch()env.MYBROWSERpuppeteer.launch()chromium.launch()解决方案:
typescript
// ❌ 缺少浏览器绑定
const browser = await puppeteer.launch(); // 错误!
// ❌ 错误用法 - 尝试直接在Fetcher上调用launch()
const browser = await env.MYBROWSER.launch(); // "RPC receiver does not implement the method 'launch'"
// ✅ 将绑定传递给Puppeteer/Playwright包装函数
const browser = await puppeteer.launch(env.MYBROWSER);
// 或Playwright用法:
const browser = await chromium.launch(env.MYBROWSER);TypeScript类型说明:
typescript
interface Env {
MYBROWSER: Fetcher; // 这是Fetcher,不是Browser实例!
}Issue #3: Browser Timeout (60 seconds)
问题#3:浏览器超时(60秒)
Error: Browser closes unexpectedly after 60 seconds
Source: https://developers.cloudflare.com/browser-rendering/platform/limits/#note-on-browser-timeout
Why It Happens: Default timeout is 60 seconds of inactivity
Prevention: Use option to extend up to 10 minutes
keep_aliveSolution:
typescript
// Extend timeout to 5 minutes for long-running tasks
const browser = await puppeteer.launch(env.MYBROWSER, {
keep_alive: 300000 // 5 minutes = 300,000 ms
});Note: Browser closes if no devtools commands for the specified duration.
错误现象: 浏览器在60秒后意外关闭
来源: https://developers.cloudflare.com/browser-rendering/platform/limits/#note-on-browser-timeout
原因: 默认超时为60秒无活动时间
预防方案: 使用选项将超时延长至10分钟
keep_alive解决方案:
typescript
// 为长时间运行的任务将超时延长至5分钟
const browser = await puppeteer.launch(env.MYBROWSER, {
keep_alive: 300000 // 5分钟 = 300,000毫秒
});注意: 如果在指定时长内没有devtools命令,浏览器将关闭。
Issue #4: Concurrency Limits Reached
问题#4:达到并发限制
Error: "Rate limit exceeded" or new browser launch fails
Source: https://developers.cloudflare.com/browser-rendering/platform/limits/, Changelog 2025-09-25
Why It Happens: Exceeded concurrent browser limit (3 free, 30 paid as of Sept 2025)
Prevention: Reuse sessions, use tabs instead of multiple browsers, check limits before launching, throttle requests to per-second rate
Solutions:
typescript
// 1. Check limits before launching
const limits = await puppeteer.limits(env.MYBROWSER);
if (limits.allowedBrowserAcquisitions === 0) {
return new Response("Concurrency limit reached", { status: 429 });
}
// 2. Reuse sessions
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
if (freeSessions.length > 0) {
const browser = await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
}
// 3. Use tabs instead of multiple browsers
const browser = await puppeteer.launch(env.MYBROWSER);
const page1 = await browser.newPage();
const page2 = await browser.newPage(); // Same browser, different tabs错误信息: "Rate limit exceeded" 或新浏览器启动失败
来源: https://developers.cloudflare.com/browser-rendering/platform/limits/, Changelog 2025-09-25
原因: 超出浏览器并发限制(截至2025年9月,免费版3个,付费版30个)
预防方案: 复用会话、使用标签页而非多个浏览器、启动前检查限制、按每秒速率节流请求
解决方案:
typescript
// 1. 启动前检查限制
const limits = await puppeteer.limits(env.MYBROWSER);
if (limits.allowedBrowserAcquisitions === 0) {
return new Response("达到并发限制", { status: 429 });
}
// 2. 复用会话
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
if (freeSessions.length > 0) {
const browser = await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
}
// 3. 使用标签页而非多个浏览器
const browser = await puppeteer.launch(env.MYBROWSER);
const page1 = await browser.newPage();
const page2 = await browser.newPage(); // 同一浏览器,不同标签页Issue #5: Local Development Request Size Limit
问题#5:本地开发请求大小限制
Error: Request larger than 1MB fails in
Source: https://developers.cloudflare.com/browser-rendering/faq/#does-local-development-support-all-browser-rendering-features
Why It Happens: Local development limitation
Prevention: Use in browser binding for local dev
wrangler devremote: trueSolution:
jsonc
// wrangler.jsonc for local development
{
"browser": {
"binding": "MYBROWSER",
"remote": true // Use real headless browser during dev
}
}错误现象: 在中,大于1MB的请求失败
来源: https://developers.cloudflare.com/browser-rendering/faq/#does-local-development-support-all-browser-rendering-features
原因: 本地开发的限制
预防方案: 在浏览器绑定中设置用于本地开发
wrangler devremote: true解决方案:
jsonc
// 本地开发用wrangler.jsonc
{
"browser": {
"binding": "MYBROWSER",
"remote": true // 开发时使用真实无头浏览器
}
}Issue #6: Bot Protection Always Triggered
问题#6:始终触发机器人防护
Error: Website blocks requests as bot traffic
Source: https://developers.cloudflare.com/browser-rendering/faq/#will-browser-rendering-bypass-cloudflares-bot-protection
Why It Happens: Browser Rendering requests always identified as bots
Prevention: Cannot bypass; if scraping your own zone, create WAF skip rule (requires Enterprise plan for Bot Management)
Solution:
typescript
// ❌ Cannot bypass bot protection
// Requests will always be identified as bots
// ✅ If scraping your own Cloudflare zone (Enterprise plan only):
// 1. Go to Security > WAF > Custom rules
// 2. Create skip rule with custom header:
// Header: X-Custom-Auth
// Value: your-secret-token
// 3. Pass header in your scraping requests
await page.setExtraHTTPHeaders({
'X-Custom-Auth': 'your-secret-token'
});
// Note: Automatic headers are included:
// - cf-biso-request-id
// - cf-biso-devtoolsImportant: Free/Pro/Business plans CANNOT bypass bot detection even on their own sites. Enterprise plan with Bot Management is required for WAF allowlisting.
错误现象: 网站将请求识别为机器人流量并阻止
来源: https://developers.cloudflare.com/browser-rendering/faq/#will-browser-rendering-bypass-cloudflares-bot-protection
原因: 浏览器渲染请求始终会被识别为机器人
预防方案: 无法绕过;如果爬取自己的站点,可创建WAF跳过规则(需要企业版Bot Management)
解决方案:
typescript
// ❌ 无法绕过机器人防护
// 请求始终会被识别为机器人
// ✅ 如果爬取自己的Cloudflare站点(仅企业版支持):
// 1. 进入Security > WAF > Custom rules
// 2. 创建跳过规则,使用自定义请求头:
// 请求头:X-Custom-Auth
// 值:your-secret-token
// 3. 在爬取请求中传递该请求头
await page.setExtraHTTPHeaders({
'X-Custom-Auth': 'your-secret-token'
});
// 注意:会自动包含以下请求头:
// - cf-biso-request-id
// - cf-biso-devtools重要提示: 免费版/专业版/商业版即使爬取自己的站点也无法绕过机器人检测。需要企业版Bot Management才能配置WAF允许规则。
Issue #7: page.evaluate() Function Name Injection (__name Error)
问题#7:page.evaluate()函数名注入(__name错误)
Error:
Source: GitHub Issue #7107
Why It Happens: esbuild minification (wrangler 3.80.1+) injects helper calls in arrow functions with nested function declarations. These run in browser context where the helper doesn't exist.
Prevention: Keep functions simple - avoid nested function declarations
Applies to: wrangler 3.80.1 - 3.83.0 (fixed in 3.83.0+)
ReferenceError: __name is not defined__name()page.evaluate()Solution:
typescript
// ❌ Avoid nested function declarations
const data = await page.evaluate(async () => {
function toNumber(str: string | undefined): number | undefined {
const num = typeof str === 'string' ? str.replaceAll('.', '').replaceAll(',', '.').match(/[+-]?([0-9]*[.])?[0-9]+/) : false;
if (num) {
return Number(num[0]);
} else {
return undefined;
}
}
return toNumber('123.456');
});
// Error: ReferenceError: __name is not defined
// ✅ Inline the logic without nested functions
const data = await page.evaluate(async () => {
const str = '123.456';
const num = typeof str === 'string' ? str.replaceAll('.', '').replaceAll(',', '.').match(/[+-]?([0-9]*[.])?[0-9]+/) : false;
return num ? Number(num[0]) : undefined;
});
// ✅ Or update to wrangler 3.83.0+
// npm install wrangler@latestNote: This also affects with complex callbacks. Fixed in wrangler 3.83.0+ (Nov 2024).
page.waitForSelector()错误信息:
来源: GitHub Issue #7107
原因: esbuild压缩(wrangler 3.80.1+)会在包含嵌套函数声明的箭头函数中注入辅助调用。这些调用在浏览器上下文中运行时,该辅助函数不存在。
预防方案: 保持函数简洁 - 避免嵌套函数声明
影响版本: wrangler 3.80.1 - 3.83.0(3.83.0+已修复)
ReferenceError: __name is not defined__name()page.evaluate()解决方案:
typescript
// ❌ 避免嵌套函数声明
const data = await page.evaluate(async () => {
function toNumber(str: string | undefined): number | undefined {
const num = typeof str === 'string' ? str.replaceAll('.', '').replaceAll(',', '.').match(/[+-]?([0-9]*[.])?[0-9]+/) : false;
if (num) {
return Number(num[0]);
} else {
return undefined;
}
}
return toNumber('123.456');
});
// 错误:ReferenceError: __name is not defined
// ✅ 内联逻辑,不使用嵌套函数
const data = await page.evaluate(async () => {
const str = '123.456';
const num = typeof str === 'string' ? str.replaceAll('.', '').replaceAll(',', '.').match(/[+-]?([0-9]*[.])?[0-9]+/) : false;
return num ? Number(num[0]) : undefined;
});
// ✅ 或升级到wrangler 3.83.0+
// npm install wrangler@latest注意: 这也会影响带有复杂回调的。该问题已在wrangler 3.83.0+(2024年11月)中修复。
page.waitForSelector()Issue #8: waitForSelector() Timeout Behavior Changed
问题#8:waitForSelector()超时行为变更
Error: Code that relied on indefinite waiting now times out
Source: Changelog 2026-01-07
Why It Happens: previously did NOT timeout when selectors weren't found (hung indefinitely). This was fixed to properly honor timeout values.
Prevention: Always set explicit timeouts and handle timeout errors
Applies to: All code written before Jan 2026 that relied on indefinite waiting
waitForSelector()Solution:
typescript
// ❌ Old behavior - would hang forever if selector not found
await page.waitForSelector('#dynamic-element');
// ✅ New behavior - properly times out (set explicit timeout)
try {
await page.waitForSelector('#dynamic-element', { timeout: 5000 });
} catch (error) {
if (error.name === 'TimeoutError') {
console.log('Element not found within 5 seconds');
// Handle missing element gracefully
} else {
throw error;
}
}
// ✅ Use longer timeout for slow-loading elements
await page.waitForSelector('#slow-element', { timeout: 30000 }); // 30 secondsNote: This is a breaking fix (behavior change). Code that relied on indefinite waiting will now timeout and throw errors. Always handle gracefully.
TimeoutError错误现象: 依赖无限等待的代码现在会超时
来源: Changelog 2026-01-07
原因: 之前在未找到选择器时不会超时(无限挂起)。现在已修复为正确遵守超时设置。
预防方案: 始终设置显式超时并处理超时错误
影响范围: 2026年1月前编写的依赖无限等待的代码
waitForSelector()解决方案:
typescript
// ❌ 旧行为 - 如果未找到元素会无限挂起
await page.waitForSelector('#dynamic-element');
// ✅ 新行为 - 正确超时(设置显式超时)
try {
await page.waitForSelector('#dynamic-element', { timeout: 5000 });
} catch (error) {
if (error.name === 'TimeoutError') {
console.log('5秒内未找到元素');
// 优雅处理元素缺失情况
} else {
throw error;
}
}
// ✅ 为加载缓慢的元素设置更长超时
await page.waitForSelector('#slow-element', { timeout: 30000 }); // 30秒注意: 这是一个破坏性修复(行为变更)。依赖无限等待的代码现在会超时并抛出错误。请始终优雅处理。
TimeoutErrorProduction Checklist
生产环境检查清单
Before deploying Browser Rendering Workers to production:
在将浏览器渲染Workers部署到生产环境前,请完成以下检查:
Configuration
配置
- Browser binding configured in wrangler.jsonc
- nodejs_compat flag enabled (required for Browser Rendering)
- Keep-alive timeout set if tasks take > 60 seconds
- Remote binding enabled for local development if needed
- 已配置浏览器绑定 在wrangler.jsonc中
- 已启用nodejs_compat标志(浏览器渲染必需)
- 已设置保持活跃超时 如果任务耗时超过60秒
- 已启用远程绑定 如需本地开发使用
Error Handling
错误处理
- Retry logic implemented for rate limits
- Timeout handling for page.goto()
- Browser cleanup in try-finally blocks
- Concurrency limit checks before launching browsers
- Graceful degradation when browser unavailable
- 已实现重试逻辑 针对速率限制
- 已处理超时 针对page.goto()
- 已在try-finally块中清理浏览器资源
- 已在启动浏览器前检查并发限制
- 已实现优雅降级 当浏览器不可用时
Performance
性能
- Session reuse implemented for high-traffic routes
- Multiple tabs used instead of multiple browsers
- Incognito contexts for session isolation
- KV caching for repeated screenshots/PDFs
- Batch operations to maximize browser utilization
- 已实现会话复用 针对高流量路由
- 已使用多标签页 而非多个浏览器
- 已使用隐身上下文 用于会话隔离
- 已使用KV缓存 针对重复的截图/PDF
- 已实现批量操作 最大化浏览器利用率
Monitoring
监控
- Log browser session IDs for debugging
- Track browser duration for billing estimates
- Monitor concurrency usage with puppeteer.limits()
- Alert on rate limit errors
- Dashboard monitoring at https://dash.cloudflare.com/?to=/:account/workers/browser-rendering
- 已记录浏览器会话ID 用于调试
- 已跟踪浏览器运行时长 用于计费估算
- 已通过puppeteer.limits()监控并发使用情况
- 已设置速率限制错误告警
- 已配置仪表板监控 地址:https://dash.cloudflare.com/?to=/:account/workers/browser-rendering
Security
安全
- Input validation for URLs (prevent SSRF)
- Timeout limits to prevent abuse
- Rate limiting on public endpoints
- Authentication for sensitive scraping endpoints
- WAF rules if scraping your own zone
- 已验证URL输入 防止SSRF攻击
- 已设置超时限制 防止滥用
- 已在公共端点设置速率限制
- 已为敏感爬取端点添加认证
- 已配置WAF规则 如果爬取自己的站点
Testing
测试
- Test screenshot capture with various page sizes
- Test PDF generation with custom HTML
- Test scraping with dynamic content (networkidle0)
- Test error scenarios (invalid URLs, timeouts)
- Load test concurrency limits
- 已测试不同页面尺寸的截图捕获
- 已测试自定义HTML的PDF生成
- 已测试动态内容爬取(使用networkidle0)
- 已测试错误场景(无效URL、超时)
- 已进行负载测试 验证并发限制
Error Handling Best Practices
错误处理最佳实践
Production Pattern - Use try-catch with proper cleanup:
typescript
async function withBrowser<T>(env: Env, fn: (browser: Browser) => Promise<T>): Promise<T> {
let browser: Browser | null = null;
try {
// 1. Check limits before launching
const limits = await puppeteer.limits(env.MYBROWSER);
if (limits.allowedBrowserAcquisitions === 0) {
throw new Error("Rate limit reached");
}
// 2. Try session reuse first
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
browser = freeSessions.length > 0
? await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId)
: await puppeteer.launch(env.MYBROWSER);
// 3. Execute user function
const result = await fn(browser);
// 4. Disconnect (keep alive)
await browser.disconnect();
return result;
} catch (error) {
// 5. Close on error
if (browser) await browser.close();
throw error;
}
}Key Principles: Check limits → Reuse sessions → Execute → Disconnect on success, close on error
生产环境模式 - 使用try-catch并正确清理资源:
typescript
async function withBrowser<T>(env: Env, fn: (browser: Browser) => Promise<T>): Promise<T> {
let browser: Browser | null = null;
try {
// 1. 启动前检查限制
const limits = await puppeteer.limits(env.MYBROWSER);
if (limits.allowedBrowserAcquisitions === 0) {
throw new Error("达到速率限制");
}
// 2. 优先尝试会话复用
const sessions = await puppeteer.sessions(env.MYBROWSER);
const freeSessions = sessions.filter(s => !s.connectionId);
browser = freeSessions.length > 0
? await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId)
: await puppeteer.launch(env.MYBROWSER);
// 3. 执行用户函数
const result = await fn(browser);
// 4. 断开连接(保持会话活跃)
await browser.disconnect();
return result;
} catch (error) {
// 5. 出错时关闭会话
if (browser) await browser.close();
throw error;
}
}核心原则:检查限制 → 复用会话 → 执行操作 → 成功时断开连接,出错时关闭会话
Using Bundled Resources
使用附带资源
Templates (templates/)
模板(templates/)
Ready-to-use code templates for common patterns:
- - Minimal screenshot example
basic-screenshot.ts - - Screenshot with KV caching
screenshot-with-kv-cache.ts - - Generate PDFs from HTML or URLs
pdf-generation.ts - - Basic web scraping pattern
web-scraper-basic.ts - - Batch scrape multiple URLs
web-scraper-batch.ts - - Session reuse for performance
session-reuse.ts - - Scraping with Workers AI
ai-enhanced-scraper.ts - - Playwright alternative example
playwright-example.ts - - Browser binding configuration
wrangler-browser-config.jsonc
Usage:
bash
undefined针对常见模式的即用型代码模板:
- - 极简截图示例
basic-screenshot.ts - - 结合KV缓存的截图
screenshot-with-kv-cache.ts - - 从HTML或URL生成PDF
pdf-generation.ts - - 基础网页爬取模式
web-scraper-basic.ts - - 批量爬取多个URL
web-scraper-batch.ts - - 会话复用提升性能
session-reuse.ts - - 结合Workers AI的爬取
ai-enhanced-scraper.ts - - Playwright替代方案示例
playwright-example.ts - - 浏览器绑定配置
wrangler-browser-config.jsonc
使用方法:
bash
undefinedCopy template to your project
复制模板到你的项目
cp ~/.claude/skills/cloudflare-browser-rendering/templates/basic-screenshot.ts src/index.ts
undefinedcp ~/.claude/skills/cloudflare-browser-rendering/templates/basic-screenshot.ts src/index.ts
undefinedReferences (references/)
参考文档(references/)
Deep-dive documentation:
- - Complete session reuse guide
session-management.md - - Detailed pricing breakdown
pricing-and-limits.md - - All known issues and solutions
common-errors.md - - Feature comparison and migration
puppeteer-vs-playwright.md
When to load: Reference when implementing advanced patterns or debugging specific issues.
深度文档:
- - 完整会话复用指南
session-management.md - - 详细定价说明
pricing-and-limits.md - - 所有已知问题及解决方案
common-errors.md - - 特性对比与迁移指南
puppeteer-vs-playwright.md
加载时机: 实现高级模式或排查特定问题时参考。
Dependencies
依赖项
Required:
- - Puppeteer for Workers
@cloudflare/puppeteer@1.0.4 - - Cloudflare CLI
wrangler@4.43.0+
Optional:
- - Playwright for Workers (alternative)
@cloudflare/playwright@1.0.0 - - TypeScript types
@cloudflare/workers-types@4.20251014.0+
Related Skills:
- - Worker setup with Hono
cloudflare-worker-base - - KV caching for screenshots
cloudflare-kv - - R2 storage for generated files
cloudflare-r2 - - AI-enhanced scraping
cloudflare-workers-ai
必需:
- - 适用于Workers的Puppeteer
@cloudflare/puppeteer@1.0.4 - - Cloudflare命令行工具
wrangler@4.43.0+
可选:
- - 适用于Workers的Playwright(替代方案)
@cloudflare/playwright@1.0.0 - - TypeScript类型定义
@cloudflare/workers-types@4.20251014.0+
相关技能:
- - 使用Hono的Worker配置
cloudflare-worker-base - - 截图的KV缓存
cloudflare-kv - - 生成文件的R2存储
cloudflare-r2 - - AI增强型爬取
cloudflare-workers-ai
Official Documentation
官方文档
- Browser Rendering Docs: https://developers.cloudflare.com/browser-rendering/
- Puppeteer API: https://pptr.dev/api/
- Playwright API: https://playwright.dev/docs/api/class-playwright
- Cloudflare Puppeteer Fork: https://github.com/cloudflare/puppeteer
- Cloudflare Playwright Fork: https://github.com/cloudflare/playwright
- Pricing: https://developers.cloudflare.com/browser-rendering/platform/pricing/
- Limits: https://developers.cloudflare.com/browser-rendering/platform/limits/
- 浏览器渲染文档:https://developers.cloudflare.com/browser-rendering/
- Puppeteer API:https://pptr.dev/api/
- Playwright API:https://playwright.dev/docs/api/class-playwright
- Cloudflare Puppeteer分支:https://github.com/cloudflare/puppeteer
- Cloudflare Playwright分支:https://github.com/cloudflare/playwright
- 定价:https://developers.cloudflare.com/browser-rendering/platform/pricing/
- 限制:https://developers.cloudflare.com/browser-rendering/platform/limits/
Package Versions (Verified 2026-01-21)
已验证的包版本(2026-01-21)
json
{
"dependencies": {
"@cloudflare/puppeteer": "^1.0.4"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20251014.0",
"wrangler": "^4.59.3"
}
}Alternative (Playwright):
json
{
"dependencies": {
"@cloudflare/playwright": "^1.1.0"
}
}Note: Playwright v1.1.0 includes support for Playwright v1.57 (Jan 2026). Wrangler 3.83.0+ fixes the __name injection bug.
page.evaluate()json
{
"dependencies": {
"@cloudflare/puppeteer": "^1.0.4"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20251014.0",
"wrangler": "^4.59.3"
}
}替代方案(Playwright):
json
{
"dependencies": {
"@cloudflare/playwright": "^1.1.0"
}
}注意: Playwright v1.1.0包含对Playwright v1.57的支持(2026年1月更新)。Wrangler 3.83.0+修复了的__name注入问题。
page.evaluate()Troubleshooting
故障排除
Problem: "Cannot read properties of undefined (reading 'fetch')"
问题:"Cannot read properties of undefined (reading 'fetch')"
Solution: Pass browser binding to puppeteer.launch():
typescript
const browser = await puppeteer.launch(env.MYBROWSER); // Not just puppeteer.launch()解决方案: 将浏览器绑定传递给puppeteer.launch():
typescript
const browser = await puppeteer.launch(env.MYBROWSER); // 不要只调用puppeteer.launch()Problem: XPath selectors not working
问题:XPath选择器无法工作
Solution: Use CSS selectors or page.evaluate() with XPathEvaluator (see Issue #1)
解决方案: 使用CSS选择器或在page.evaluate()中使用XPathEvaluator(详见问题#1)
Problem: Browser closes after 60 seconds
问题:浏览器60秒后关闭
Solution: Extend timeout with keep_alive:
typescript
const browser = await puppeteer.launch(env.MYBROWSER, { keep_alive: 300000 });解决方案: 使用keep_alive延长超时:
typescript
const browser = await puppeteer.launch(env.MYBROWSER, { keep_alive: 300000 });Problem: Rate limit reached
问题:达到速率限制
Solution: Reuse sessions, use tabs, check limits before launching (see Issue #4)
解决方案: 复用会话、使用标签页、启动前检查限制(详见问题#4)
Problem: Local dev request > 1MB fails
问题:本地开发中大于1MB的请求失败
Solution: Enable remote binding in wrangler.jsonc:
jsonc
{ "browser": { "binding": "MYBROWSER", "remote": true } }解决方案: 在wrangler.jsonc中启用远程绑定:
jsonc
{ "browser": { "binding": "MYBROWSER", "remote": true } }Problem: Website blocks as bot
问题:网站将请求识别为机器人并阻止
Solution: Cannot bypass. If your own zone, create WAF skip rule (see Issue #6)
Questions? Issues?
- Check for detailed solutions
references/common-errors.md - Review for performance optimization
references/session-management.md - Verify browser binding is configured in wrangler.jsonc
- Check official docs: https://developers.cloudflare.com/browser-rendering/
- Ensure compatibility flag is enabled
nodejs_compat
解决方案: 无法绕过。如果是自己的站点,创建WAF跳过规则(详见问题#6)
有疑问?遇到问题?
- 查看获取详细解决方案
references/common-errors.md - 查看获取性能优化建议
references/session-management.md - 验证wrangler.jsonc中是否已配置浏览器绑定
- 查看官方文档:https://developers.cloudflare.com/browser-rendering/
- 确保已启用兼容性标志
nodejs_compat