# Browser Rendering Patterns ## Basic Worker ```typescript import puppeteer from "@cloudflare/puppeteer"; export default { async fetch(request, env) { const browser = await puppeteer.launch(env.MYBROWSER); try { const page = await browser.newPage(); await page.goto("https://example.com"); return new Response(await page.content()); } finally { await browser.close(); // ALWAYS in finally } } }; ``` ## Session Reuse Keep sessions alive for performance: ```typescript let sessionId = await env.SESSION_KV.get("browser-session"); if (sessionId) { browser = await puppeteer.connect(env.MYBROWSER, sessionId); } else { browser = await puppeteer.launch(env.MYBROWSER, { keep_alive: 600000 }); await env.SESSION_KV.put("browser-session", browser.sessionId(), { expirationTtl: 600 }); } // Don't close browser to keep session alive ``` ## Common Operations | Task | Code | |------|------| | Screenshot | `await page.screenshot({ type: "png", fullPage: true })` | | PDF | `await page.pdf({ format: "A4", printBackground: true })` | | Extract data | `await page.evaluate(() => document.querySelector('h1').textContent)` | | Fill form | `await page.type('#input', 'value'); await page.click('button')` | | Wait nav | `await Promise.all([page.waitForNavigation(), page.click('a')])` | ## Parallel Scraping ```typescript const pages = await Promise.all(urls.map(() => browser.newPage())); await Promise.all(pages.map((p, i) => p.goto(urls[i]))); const titles = await Promise.all(pages.map(p => p.title())); ``` ## Playwright Selectors ```typescript import { launch } from "@cloudflare/playwright"; const browser = await launch(env.MYBROWSER); await page.getByRole("button", { name: "Sign in" }).click(); await page.getByLabel("Email").fill("user@example.com"); await page.getByTestId("submit-button").click(); ``` ## Incognito Contexts Isolated sessions without multiple browsers: ```typescript const ctx1 = await browser.createIncognitoBrowserContext(); const ctx2 = await browser.createIncognitoBrowserContext(); // Each has isolated cookies/storage ``` ## Quota Check ```typescript const limits = await puppeteer.limits(env.MYBROWSER); if (limits.remaining < 60000) return new Response("Quota low", { status: 429 }); ``` ## Error Handling ```typescript try { await page.goto(url, { timeout: 30000, waitUntil: "networkidle0" }); } catch (e) { if (e.message.includes("timeout")) return new Response("Timeout", { status: 504 }); if (e.message.includes("Session limit")) return new Response("Too many sessions", { status: 429 }); } finally { if (browser) await browser.close(); } ```