Why Playwright `connectOverCDP`?
Playwright provides a dedicated method called chromium.connectOverCDP(endpointURL) specifically designed for connecting to remote Chrome instances over WebSocket. This approach offers several massive advantages over local browser execution:
- Zero Chromium Downloads in CI/CD: Your Docker images and GitHub Actions don't need to install 400MB of browser binaries or OS dependencies.
- Automatic Fingerprint Spoofing: Cloud browsers inject realistic canvas, WebGL, WebRTC, and hardware concurrency fingerprints to prevent bot detection.
- Built-in Residential Proxies: Every request is routed through verified residential IPs across 220+ countries.
TypeScript / Node.js Implementation
import { chromium } from 'playwright';
const API_KEY = process.env.TWOCAPTCHA_API_KEY || 'YOUR_2CAPTCHA_KEY';
const cdpUrl = `wss://browser.2captcha.com/connect?apiKey=${API_KEY}&autoSolve=true`;
async function run() {
console.log('Connecting Playwright to 2Captcha Browser...');
const browser = await chromium.connectOverCDP(cdpUrl);
try {
const context = browser.contexts()[0] || await browser.newContext();
const page = await context.newPage();
console.log('Visiting target ecommerce site...');
await page.goto('https://nowsecure.nl', { waitUntil: 'domcontentloaded' });
// Wait for the anti-bot challenge to be cleared automatically
await page.waitForTimeout(4000);
const title = await page.title();
console.log('Successfully loaded page:', title);
await page.screenshot({ path: 'playwright-result.png' });
} finally {
await browser.close();
}
}
run().catch(console.error);Python Implementation
For data science and Python scraping teams, the setup in playwright.sync_api or async_api is equally simple:
import os
from playwright.sync_api import sync_playwright
API_KEY = os.getenv("TWOCAPTCHA_API_KEY", "YOUR_2CAPTCHA_KEY")
cdp_url = f"wss://browser.2captcha.com/connect?apiKey={API_KEY}&autoSolve=true"
with sync_playwright() as p:
print("Connecting to 2Captcha Cloud Browser...")
browser = p.chromium.connect_over_cdp(cdp_url)
context = browser.contexts[0] if browser.contexts else browser.new_context()
page = context.new_page()
page.goto("https://nowsecure.nl")
page.wait_for_timeout(3000)
print(f"Page Title: {page.title()}")
page.screenshot(path="python_scraped.png")
browser.close()
print("Session closed successfully.")Comparison: Playwright on Local Server vs 2Captcha Browser API
| Feature | Local Playwright | 2Captcha Browser API (#1) |
|---|---|---|
| RAM Usage per Thread | 250MB–450MB on host | 0MB (Cloud offloaded) |
| Cloudflare Turnstile Bypass | Fails / Blocked | 100% Native Automated |
| Residential Proxy Rotation | Requires external config | Built-in (220+ Countries) |
| Cost Model | Server hosting costs | $0.15/hour (Pay-As-You-Go) |