HomeFeaturesAbout UsMarketplacePricingBlogDocs
Docs/Automation & APIs

Playwright Stealth Bypass Cloudflare: Developer Integration Guide

Build undetectable web scrapers using Playwright and BrowserMesh CloakBrowser. Bypass Cloudflare Turnstile, emit structured records, and run with $0 proxy bills.

How to Build Resilient Web Automation Plugins Using Playwright Core and BrowserMesh CloakBrowser Engine.

While Microsoft Playwright is the industry standard for modern browser automation, standard Playwright instances get flagged almost instantly when navigating pages protected by Cloudflare Turnstile, DataDome, or Akamai.

Common community workarounds (such as puppeteer-extra-plugin-stealth or vanilla Playwright script injection) often fail because modern anti-bot systems detect:

  1. Native Chrome DevTools Protocol (CDP) debugging artifacts (Runtime.enable).
  2. Discrepancies between JavaScript prototype overrides and native C++ browser behavior.
  3. Requests originating from known data center hosting IP subnets.

BrowserMesh solves this by natively pairing Playwright Core with CloakBrowser—our custom stealth Chromium binary executed directly on authentic edge hardware (your laptop, desktop, or mobile device).


1. The BrowserMesh Plugin Architecture

In BrowserMesh, you do not need to manage browser launching boilerplate, WebSocket screencasting, database connections, or CSV/Excel exporters. The BrowserMesh runtime injects an instrumented context object directly into your scraper's run() function:

BrowserMesh Runtime
┌─────────────────────────────────────────────────────────────────────────┐
│                          BrowserMesh Runtime                            │
│   (CloakBrowser Launch • Local SQLite DB • Live WebSocket Screencast)    │
└────────────────────────────────────┬────────────────────────────────────┘
                                     │ Passes Stealth 'context'
                                     ▼
                     ┌───────────────────────────────┐
                     │    Your Playwright Plugin     │
                     │       run(context) async      │
                     └───────────────┬───────────────┘
                                     │ Emits records
                                     ▼
                     context.emit('result', record);
                                     │
                     ┌───────────────┴───────────────┐
                     │ • SHA-256 Deduplication       │
                     │ • Local SQLite Persistence    │
                     │ • Live UI Table Updates       │
                     │ • 1-Click Excel / CSV Exports │
                     └───────────────────────────────┘

2. Writing a Stealth Scraper with Playwright Core

Here is a complete, production-ready BrowserMesh scraper plugin written in TypeScript / JavaScript:

Terminal / Code
import { PlaywrightContext } from '@browsermesh/sdk';

export interface ScraperInput {
  targetUrl: string;
  maxPages?: number;
  searchKeyword?: string;
}

/**
 * Main execution entrypoint for BrowserMesh Scraper Plugin
 */
export async function run(context: PlaywrightContext<ScraperInput>) {
  const { page, logger, inputs } = context;
  const maxPages = inputs.maxPages || 3;

  logger.info(`Starting stealth extraction on: ${inputs.targetUrl}`);

  // 1. Navigate to target URL using CloakBrowser stealth context
  await page.goto(inputs.targetUrl, {
    waitUntil: 'domcontentloaded',
    timeout: 30000,
  });

  // 2. CloakBrowser automatically handles passive Turnstile challenges
  // If an interactive puzzle surfaces, the 30+ FPS screencast displays it in Studio
  await page.waitForSelector('.product-grid, .results-container', { timeout: 15000 });

  let currentPage = 1;

  while (currentPage <= maxPages) {
    logger.info(`Extracting page ${currentPage} of ${maxPages}...`);

    // Extract records using standard Playwright selectors
    const items = await page.$$eval('.product-card', (cards) => {
      return cards.map((card) => {
        const titleEl = card.querySelector('.product-title');
        const priceEl = card.querySelector('.price-tag');
        const linkEl = card.querySelector('a.product-link') as HTMLAnchorElement;

        return {
          title: titleEl ? titleEl.textContent?.trim() : '',
          price: priceEl ? priceEl.textContent?.trim() : '',
          productUrl: linkEl ? linkEl.href : '',
          scrapedAt: new Date().toISOString(),
        };
      });
    });

    // 3. Emit each extracted record to the BrowserMesh engine
    // BrowserMesh automatically deduplicates (SHA-256) and stores locally
    for (const item of items) {
      if (item.title && item.productUrl) {
        await context.emit('result', item);
      }
    }

    // Check for pagination
    const nextButton = await page.$('a.pagination-next:not(.disabled)');
    if (!nextButton || currentPage >= maxPages) {
      break;
    }

    // Emulate natural human click with Bezier curve dynamics
    await nextButton.click();
    await page.waitForLoadState('domcontentloaded');
    currentPage++;
  }

  logger.info(`Job completed successfully! Total pages scraped: ${currentPage}`);
}

3. The Scraper Manifest: manifest.json

Every plugin package includes a manifest.json file defining its parameters and user interface schema:

Terminal / Code
{
  "id": "playwright-stealth-demo",
  "name": "E-Commerce Stealth Extractor",
  "version": "1.0.0",
  "author": "Data Engineering Team",
  "category": "E-Commerce",
  "stealthLevel": 3,
  "inputs": [
    {
      "name": "targetUrl",
      "type": "string",
      "label": "Target Catalog URL",
      "placeholder": "https://example.com/products",
      "required": true
    },
    {
      "name": "maxPages",
      "type": "number",
      "label": "Max Pages to Crawl",
      "default": 3,
      "min": 1,
      "max": 50
    }
  ],
  "outputs": [
    "title",
    "price",
    "productUrl",
    "scrapedAt"
  ]
}

BrowserMesh automatically converts this schema into:

  • The Visual Form Launcher in the Studio interface (/scrapers/:id/run).
  • The Code Editor JSON View for programmatic inputs.
  • The "Copy AI Prompt" Template allowing users to generate input configurations with ChatGPT or Claude.

4. Deploying Your Custom Plugin Locally

  1. Create a new directory inside your local BrowserMesh companion data path:
    • Windows: %LOCALAPPDATA%\BrowserMesh\scraper_data\plugins\my-custom-scraper
    • Linux / VPS: ~/.browsermesh/scraper_data/plugins/my-custom-scraper
  2. Place your manifest.json and compiled index.js into this folder.
  3. Open https://studio.browsermesh.in and navigate to Scrapers Catalog.
  4. Your custom plugin appears immediately in your library, ready to execute with CloakBrowser stealth protection!

5. Why CloakBrowser Outperforms Vanilla Playwright

Feature / CapabilityVanilla Playwright (@playwright/test)BrowserMesh + CloakBrowser
Execution LocationCloud Data Centers (AWS / GCP)Local Edge Nodes (Home Fiber / 4G/5G)
Cloudflare TurnstileFlagged & Blocked (HTTP 403)Bypassed via CloakBrowser Native Masking
Interactive CAPTCHASilent Timeout / Script Crash30+ FPS Live Canvas Screencast with 1-Click Solving
Mouse TrajectoriesInstant Coordinate TeleportationHumanized Cubic Bezier Dynamics & Jitter
Data StorageManual DB Scripting RequiredZero-Config Embedded SQLite Database
Proxy Bandwidth Costs$10–$25 per GB$0 (Uses Authentic Local Residential IP)

Next Steps & Developer References