Skip to content

Comments

feat: add Cloudflare Containers as alternative browser provider#1

Open
dcartertwo wants to merge 2 commits intomainfrom
feat/cloudflare-browser-rendering
Open

feat: add Cloudflare Containers as alternative browser provider#1
dcartertwo wants to merge 2 commits intomainfrom
feat/cloudflare-browser-rendering

Conversation

@dcartertwo
Copy link
Owner

@dcartertwo dcartertwo commented Feb 16, 2026

Summary

Add Cloudflare Containers as a drop-in alternative to BrowserBase for running headless browser sessions. Selectable via BROWSER_PROVIDER=cloudflare env var.

Why Containers instead of Browser Rendering?

We initially built on Cloudflare Browser Rendering (Durable Object + @cloudflare/playwright), but every request was flagged as a bot because Browser Rendering injects automatic headers (cf-biso-devtools, Signature-agent, etc.) that cannot be removed. Sites with Cloudflare bot protection (Turnstile, managed challenges) blocked us immediately.

Cloudflare Containers runs standard Chromium with standard Playwright inside Docker containers on Cloudflare's edge — no bot-detection headers injected.

Architecture

React (browser) → Next.js API route (/api/chat) → Cloudflare Worker
                                                     ↓
                                                  getContainer(env.LOGIN_SESSIONS, sessionId)
                                                     ↓
                                                  Docker Container (standard-2: 1 vCPU, 6 GiB RAM)
                                                     ├── Node.js HTTP server (port 3000)
                                                     ├── Standard Playwright + system Chromium
                                                     ├── Stealth measures (navigator.webdriver, plugins, UA, etc.)
                                                     └── Same REST endpoints as original design

What's included

Next.js app changes:

  • Provider factory pattern (BROWSER_PROVIDER=browserbase|cloudflare)
  • Extracted BrowserBase provider to providers/browserbase.ts
  • New Cloudflare provider client in providers/cloudflare.ts (retry with backoff, 429 handling, SessionExpiredError)
  • BrowserSession abstraction — all browser functions take session instead of page
  • Screenshot preview (<img> fallback when no liveViewUrl)
  • Session expiry handling in frontend

Worker + Container:

  • worker/src/index.ts — Worker using getContainer() for session routing
  • worker/src/login-browser-container.ts — Container class (standard-2, 15min sleep)
  • worker/container/src/server.ts — Node.js HTTP server with all browser operations
  • worker/container/src/stealth.ts — Stealth patches (21/23 bot tests pass)
  • worker/Dockerfilenode:22-slim + system chromium (~357MB image)

Stealth results (bot.sannysoft.com)

Test Result
WebDriver (New) ✅ missing (passed)
WebDriver Advanced ✅ passed
Plugins is of type PluginArray ✅ passed
Chrome object ✅ present (passed)
17 other tests ✅ all passed
WebGL Vendor/Renderer ❌ no webgl context (expected in headless)

Testing performed

  • npm run build — zero errors
  • ✅ Worker tsc --noEmit — zero errors
  • wrangler deploy — container deployed successfully
  • ✅ Health endpoint responds
  • ✅ Session creation + page navigation (example.com)
  • ✅ Page context extraction (HTML + screenshot)
  • ✅ Bot detection tests (21/23 pass)
  • ✅ Full end-to-end via Next.js API (GitHub login page correctly identified as credential_login_form with 2 inputs + submit button)
  • ✅ Session close works cleanly
  • ✅ BrowserBase path unchanged (backward compatible)

Environment variables

# Choose provider
BROWSER_PROVIDER=cloudflare  # or "browserbase" (default)

# Cloudflare provider
CF_BROWSER_WORKER_URL=https://your-worker.workers.dev
CF_BROWSER_API_KEY=your-secret

# BrowserBase provider (unchanged)
BROWSERBASE_API_KEY=...
BROWSERBASE_PROJECT_ID=...

Add a drop-in Cloudflare Browser Rendering backend alongside
BrowserBase, selectable via BROWSER_PROVIDER env var.

Key changes:
- Refactor browser.ts into provider factory with browserbase/cloudflare providers
- Add Cloudflare Worker + Durable Object (worker/) to hold persistent browser sessions
- Extract shared DOM walker into page-extract.ts
- Add screenshot preview fallback in BrowserPreview (no live iframe for CF)
- Add retry with backoff, 429 handling, and session expiry detection
- Update README and .env.example with both provider paths

The BrowserBase path remains fully functional and is the default.
Replace the Durable Object + @cloudflare/playwright approach with
Cloudflare Containers running standard Playwright + system Chromium.
This avoids the bot-detection headers that Browser Rendering injects
(cf-biso-devtools, Signature-agent) which caused every request to be
flagged by Cloudflare's own bot protection.

- Add Docker container with Node.js HTTP server + system Chromium
- Add stealth module (navigator.webdriver, plugins, chrome.runtime, etc.)
- Replace LoginBrowserDO with LoginBrowserContainer (extends Container)
- Rewrite worker to use getContainer() instead of DO fetch
- Update wrangler.jsonc with containers config (standard-2, 6GB RAM)
- All 21/23 bot.sannysoft.com tests pass (2 WebGL failures expected)
@dcartertwo dcartertwo changed the title feat: add Cloudflare Browser Rendering as alternative provider feat: add Cloudflare Containers as alternative browser provider Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant