Reference

Chrome DevTools Protocol + CaptchaAI: Low-Level CAPTCHA Automation

Chrome DevTools Protocol (CDP) gives you direct control over Chrome at the protocol level — no WebDriver, no extra abstraction layers. For CAPTCHA automation, this means better stealth, lower overhead, and fine-grained control over network requests, page execution, and browser behavior.


Why CDP Over WebDriver?

Feature WebDriver CDP
Detection surface High (navigator.webdriver) Minimal
Network interception Requires Selenium Wire Built-in (Fetch.requestPaused)
JavaScript injection executeScript (detectable) Runtime.evaluate (stealth)
Performance overhead Medium-high Low
Protocol support HTTP + JSON Wire WebSocket (real-time)

Direct CDP Connection (Node.js)

Connect to Chrome

# Launch Chrome with remote debugging
chrome --remote-debugging-port=9222 --no-first-run --no-default-browser-check
const WebSocket = require("ws");
const http = require("http");

class CDPClient {
  constructor() {
    this.ws = null;
    this.id = 0;
    this.callbacks = new Map();
    this.eventHandlers = new Map();
  }

  async connect(port = 9222) {
    // Get WebSocket URL from Chrome
    const targets = await this.httpGet(
      `http://127.0.0.1:${port}/json/list`
    );
    const target = targets.find((t) => t.type === "page");

    return new Promise((resolve, reject) => {
      this.ws = new WebSocket(target.webSocketDebuggerUrl);
      this.ws.on("open", () => resolve());
      this.ws.on("error", reject);
      this.ws.on("message", (data) => this.handleMessage(JSON.parse(data)));
    });
  }

  httpGet(url) {
    return new Promise((resolve, reject) => {
      http.get(url, (res) => {
        let body = "";
        res.on("data", (c) => (body += c));
        res.on("end", () => resolve(JSON.parse(body)));
      }).on("error", reject);
    });
  }

  handleMessage(msg) {
    if (msg.id && this.callbacks.has(msg.id)) {
      this.callbacks.get(msg.id)(msg);
      this.callbacks.delete(msg.id);
    }
    if (msg.method && this.eventHandlers.has(msg.method)) {
      for (const handler of this.eventHandlers.get(msg.method)) {
        handler(msg.params);
      }
    }
  }

  send(method, params = {}) {
    return new Promise((resolve) => {
      const id = ++this.id;
      this.callbacks.set(id, resolve);
      this.ws.send(JSON.stringify({ id, method, params }));
    });
  }

  on(method, handler) {
    if (!this.eventHandlers.has(method)) {
      this.eventHandlers.set(method, []);
    }
    this.eventHandlers.get(method).push(handler);
  }
}

CaptchaAI + CDP Integration

const https = require("https");

class CDPCaptchaSolver {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.cdp = new CDPClient();
    this.API = "https://ocr.captchaai.com";
  }

  async init(port = 9222) {
    await this.cdp.connect(port);

    // Enable required domains
    await this.cdp.send("Page.enable");
    await this.cdp.send("Runtime.enable");
    await this.cdp.send("Network.enable");
    await this.cdp.send("DOM.enable");
  }

  async navigate(url) {
    const result = await this.cdp.send("Page.navigate", { url });
    await this.waitForLoad();
    return result;
  }

  async waitForLoad() {
    return new Promise((resolve) => {
      this.cdp.on("Page.loadEventFired", () => resolve());
    });
  }

  async detectSitekey() {
    const result = await this.cdp.send("Runtime.evaluate", {
      expression: `
        (() => {
          // reCAPTCHA
          const recaptcha = document.querySelector('[data-sitekey]');
          if (recaptcha) {
            return {
              type: 'recaptcha_v2',
              sitekey: recaptcha.getAttribute('data-sitekey'),
            };
          }

          // Turnstile
          const turnstile = document.querySelector('.cf-turnstile[data-sitekey]');
          if (turnstile) {
            return {
              type: 'turnstile',
              sitekey: turnstile.getAttribute('data-sitekey'),
            };
          }

          // reCAPTCHA v3 (script-based)
          const scripts = document.querySelectorAll('script[src*="recaptcha"]');
          for (const s of scripts) {
            const match = s.src.match(/render=([\\w-]+)/);
            if (match && match[1] !== 'explicit') {
              return { type: 'recaptcha_v3', sitekey: match[1] };
            }
          }

          return null;
        })()
      `,
      returnByValue: true,
    });

    return result.result?.value || null;
  }

  async solveCaptcha(siteUrl, sitekey, type = "recaptcha_v2") {
    const submitData = {
      key: this.apiKey,
      pageurl: siteUrl,
      json: "1",
    };

    if (type === "turnstile") {
      submitData.method = "turnstile";
      submitData.sitekey = sitekey;
    } else {
      submitData.method = "userrecaptcha";
      submitData.googlekey = sitekey;
    }

    const submitResp = await this.httpPost(
      `${this.API}/in.php`,
      submitData
    );

    if (submitResp.status !== 1) {
      throw new Error(`Submit: ${submitResp.request}`);
    }

    const taskId = submitResp.request;

    for (let i = 0; i < 60; i++) {
      await this.sleep(5000);

      const params = new URLSearchParams({
        key: this.apiKey,
        action: "get",
        id: taskId,
        json: "1",
      });

      const result = await this.httpGet(
        `${this.API}/res.php?${params}`
      );

      if (result.request === "CAPCHA_NOT_READY") continue;
      if (result.status !== 1) throw new Error(`Solve: ${result.request}`);
      return result.request;
    }

    throw new Error("Timeout");
  }

  async injectToken(token, type = "recaptcha_v2") {
    if (type === "turnstile") {
      await this.cdp.send("Runtime.evaluate", {
        expression: `
          const input = document.querySelector('input[name="cf-turnstile-response"]');
          if (input) {
            input.value = '${token}';
            input.dispatchEvent(new Event('change', { bubbles: true }));
          }
        `,
      });
    } else {
      await this.cdp.send("Runtime.evaluate", {
        expression: `
          // Set response textarea
          const textarea = document.querySelector('#g-recaptcha-response');
          if (textarea) {
            textarea.style.display = 'block';
            textarea.value = '${token}';
          }

          // Set all hidden fields
          document.querySelectorAll('[name="g-recaptcha-response"]')
            .forEach(el => { el.value = '${token}'; });

          // Trigger callback
          if (typeof ___grecaptcha_cfg !== 'undefined') {
            const clients = ___grecaptcha_cfg.clients;
            for (const key in clients) {
              const client = clients[key];
              for (const prop in client) {
                const val = client[prop];
                if (val && typeof val === 'object') {
                  for (const p in val) {
                    if (typeof val[p]?.callback === 'function') {
                      val[p].callback('${token}');
                    }
                  }
                }
              }
            }
          }
        `,
      });
    }
  }

  // Full workflow
  async solveOnPage(url) {
    await this.navigate(url);
    await this.sleep(2000);

    const captcha = await this.detectSitekey();
    if (!captcha) {
      console.log("No CAPTCHA detected");
      return null;
    }

    console.log(`Detected: ${captcha.type} (${captcha.sitekey})`);
    const token = await this.solveCaptcha(url, captcha.sitekey, captcha.type);
    await this.injectToken(token, captcha.type);
    console.log("Token injected");
    return token;
  }

  // HTTP helpers
  httpPost(url, data) {
    return new Promise((resolve, reject) => {
      const params = new URLSearchParams(data).toString();
      const u = new URL(url);
      const req = https.request({
        hostname: u.hostname, path: u.pathname,
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
      }, (res) => {
        let body = "";
        res.on("data", (c) => (body += c));
        res.on("end", () => resolve(JSON.parse(body)));
      });
      req.on("error", reject);
      req.write(params);
      req.end();
    });
  }

  httpGet(url) {
    return new Promise((resolve, reject) => {
      https.get(url, (res) => {
        let body = "";
        res.on("data", (c) => (body += c));
        res.on("end", () => resolve(JSON.parse(body)));
      }).on("error", reject);
    });
  }

  sleep(ms) {
    return new Promise((r) => setTimeout(r, ms));
  }
}

Network Interception with CDP

async function interceptCaptchaRequests(solver) {
  // Enable Fetch domain for request interception
  await solver.cdp.send("Fetch.enable", {
    patterns: [
      { urlPattern: "*recaptcha*", requestStage: "Request" },
      { urlPattern: "*turnstile*", requestStage: "Request" },
      { urlPattern: "*challenges.cloudflare.com*", requestStage: "Request" },
    ],
  });

  solver.cdp.on("Fetch.requestPaused", async (params) => {
    const { requestId, request } = params;

    console.log(`Intercepted: ${request.method} ${request.url}`);

    // Log CAPTCHA-related requests for debugging
    if (request.url.includes("userverify") || request.url.includes("reload")) {
      console.log("CAPTCHA verification request detected");
    }

    // Continue the request
    await solver.cdp.send("Fetch.continueRequest", { requestId });
  });
}

Stealth-Configuredion with CDP

async function applyStealthPatches(solver) {
  // Remove webdriver flag
  await solver.cdp.send("Page.addScriptToEvaluateOnNewDocument", {
    source: `
      Object.defineProperty(navigator, 'webdriver', {
        get: () => undefined,
      });

      // Fix chrome object
      window.chrome = { runtime: {}, loadTimes: () => ({}) };

      // Fix permissions
      const originalQuery = window.navigator.permissions.query;
      window.navigator.permissions.query = (params) => {
        if (params.name === 'notifications') {
          return Promise.resolve({ state: Notification.permission });
        }
        return originalQuery.call(navigator.permissions, params);
      };

      // Fix plugins
      Object.defineProperty(navigator, 'plugins', {
        get: () => [1, 2, 3, 4, 5],
      });

      // Fix languages
      Object.defineProperty(navigator, 'languages', {
        get: () => ['en-US', 'en'],
      });
    `,
  });
}

Python CDP Integration

import asyncio
import aiohttp
import json

class CDPCaptchaSolver:
    CAPTCHAAI_URL = "https://ocr.captchaai.com"

    def __init__(self, api_key, cdp_port=9222):
        self.api_key = api_key
        self.cdp_port = cdp_port
        self.ws = None
        self.msg_id = 0

    async def connect(self):
        async with aiohttp.ClientSession() as session:
            async with session.get(
                f"http://127.0.0.1:{self.cdp_port}/json/list"
            ) as resp:
                targets = await resp.json()

        target = next(t for t in targets if t["type"] == "page")
        self.ws = await asyncio.get_event_loop().create_connection(
            lambda: CDPProtocol(self),
            target["webSocketDebuggerUrl"],
        )

    async def send(self, method, params=None):
        self.msg_id += 1
        msg = {"id": self.msg_id, "method": method, "params": params or {}}
        self.ws.send(json.dumps(msg))
        # Wait for response (simplified)
        return await self._wait_response(self.msg_id)

    async def solve_and_inject(self, url):
        await self.send("Page.navigate", {"url": url})
        await asyncio.sleep(3)

        # Detect sitekey via Runtime.evaluate
        result = await self.send("Runtime.evaluate", {
            "expression": "document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')",
            "returnByValue": True,
        })

        sitekey = result.get("result", {}).get("value")
        if not sitekey:
            return None

        # Solve via CaptchaAI
        token = await self._solve_recaptcha(url, sitekey)

        # Inject
        await self.send("Runtime.evaluate", {
            "expression": f"""
                document.querySelector('#g-recaptcha-response').value = '{token}';
                document.querySelectorAll('[name="g-recaptcha-response"]')
                    .forEach(el => {{ el.value = '{token}'; }});
            """,
        })

        return token

    async def _solve_recaptcha(self, site_url, sitekey):
        import requests

        resp = requests.post(f"{self.CAPTCHAAI_URL}/in.php", data={
            "key": self.api_key, "method": "userrecaptcha",
            "googlekey": sitekey, "pageurl": site_url, "json": 1,
        })
        task_id = resp.json()["request"]

        for _ in range(60):
            await asyncio.sleep(5)
            resp = requests.get(f"{self.CAPTCHAAI_URL}/res.php", params={
                "key": self.api_key, "action": "get",
                "id": task_id, "json": 1,
            })
            data = resp.json()
            if data["request"] == "CAPCHA_NOT_READY":
                continue
            if data["status"] == 1:
                return data["request"]

        raise TimeoutError("CAPTCHA solve timeout")

Usage Example

// Full workflow
async function main() {
  const solver = new CDPCaptchaSolver("YOUR_API_KEY");
  await solver.init(9222);

  // Apply stealth
  await applyStealthPatches(solver);

  // Enable network monitoring
  await interceptCaptchaRequests(solver);

  // Solve CAPTCHA on target page
  const token = await solver.solveOnPage("https://example.com/login");

  if (token) {
    // Submit form
    await solver.cdp.send("Runtime.evaluate", {
      expression: `document.querySelector('form').submit()`,
    });
  }
}

main().catch(console.error);

Troubleshooting

Issue Cause Fix
Can't connect to Chrome Remote debugging not enabled Launch with --remote-debugging-port=9222
WebSocket closes Chrome crashed or tab closed Add reconnection logic
Runtime.evaluate fails Page not loaded Wait for Page.loadEventFired
CAPTCHA still detected Incomplete stealth patches Add User-Agent override, fix navigator.plugins
Token injection fails Shadow DOM contains CAPTCHA Use DOM.describeNode to traverse shadow roots

FAQ

Is CDP harder to use than WebDriver?

CDP is lower-level but more powerful. For CAPTCHA automation, the stealth advantages outweigh the complexity.

Can I use CDP with Puppeteer?

Yes — Puppeteer uses CDP under the hood. You can access the CDP session directly via page._client() or page.createCDPSession().

Does CDP work with Firefox?

Firefox has partial CDP support. For full CDP, use Chromium-based browsers.

Is CDP detection-proof?

CDP is harder to detect than WebDriver, but not invisible. Combine with fingerprint spoofing for best results.



Get protocol-level control over CAPTCHA automation — get your CaptchaAI key and integrate with Chrome DevTools Protocol.

Discussions (0)

No comments yet.

Related Posts

Reference CAPTCHA Token Injection Methods Reference
Complete reference for injecting solved CAPTCHA tokens into web pages.

Complete reference for injecting solved CAPTCHA tokens into web pages. Covers re CAPTCHA, Turnstile, and Cloud...

Automation Python reCAPTCHA v2
Apr 08, 2026
API Tutorials Proxy Authentication Methods for CaptchaAI API
Configure proxy authentication with Captcha AI — IP whitelisting, username/password, SOCKS 5, and passing proxies directly to the solving API.

Configure proxy authentication with Captcha AI — IP whitelisting, username/password, SOCKS 5, and passing prox...

Automation Python reCAPTCHA v2
Mar 09, 2026
Tutorials Pytest Fixtures for CaptchaAI API Testing
Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI.

Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI. Covers mocking, live integra...

Automation Python reCAPTCHA v2
Apr 08, 2026
Tutorials CAPTCHA Solving Fallback Chains
Implement fallback chains for CAPTCHA solving with Captcha AI.

Implement fallback chains for CAPTCHA solving with Captcha AI. Cascade through solver methods, proxy pools, an...

Automation Python reCAPTCHA v2
Apr 06, 2026
Use Cases Multi-Step Workflow Automation with CaptchaAI
Manage workflows across multiple accounts on CAPTCHA-protected platforms — , action, and data collection at scale.

Manage workflows across multiple accounts on CAPTCHA-protected platforms — , action, and data collection at sc...

Automation Python reCAPTCHA v2
Apr 06, 2026
Comparisons WebDriver vs Chrome DevTools Protocol for CAPTCHA Automation
Compare Web Driver and Chrome Dev Tools Protocol (CDP) for CAPTCHA automation — detection, performance, capabilities, and when to use each with Captcha AI.

Compare Web Driver and Chrome Dev Tools Protocol (CDP) for CAPTCHA automation — detection, performance, capabi...

Automation Python reCAPTCHA v2
Mar 27, 2026
Troubleshooting ERROR_PAGEURL: URL Mismatch Troubleshooting Guide
Fix ERROR_PAGEURL when using Captcha AI.

Fix ERROR_PAGEURL when using Captcha AI. Diagnose URL mismatch issues, handle redirects, SPAs, and dynamic URL...

Automation Python reCAPTCHA v2
Mar 23, 2026
Troubleshooting Handling reCAPTCHA v2 and Cloudflare Turnstile on the Same Site
Solve both re CAPTCHA v 2 and Cloudflare Turnstile on sites that use multiple CAPTCHA providers — detect which type appears, solve each correctly, and handle pr...

Solve both re CAPTCHA v 2 and Cloudflare Turnstile on sites that use multiple CAPTCHA providers — detect which...

Automation Python reCAPTCHA v2
Mar 23, 2026
Integrations Solving CAPTCHAs in React Native WebViews with CaptchaAI
how to detect and solve re CAPTCHA v 2 and Cloudflare Turnstile CAPTCHAs inside React Native Web Views using the Captcha AI API with working Java Script bridge...

Learn how to detect and solve re CAPTCHA v 2 and Cloudflare Turnstile CAPTCHAs inside React Native Web Views u...

Automation Python reCAPTCHA v2
Mar 30, 2026
Integrations Undetected ChromeDriver with CaptchaAI Integration
Integrate undetected-chromedriver with Captcha AI for reliable browser automation.

Integrate undetected-chromedriver with Captcha AI for reliable browser automation. Handle re CAPTCHA and Turns...

Automation Python reCAPTCHA v2
Jan 27, 2026
Reference CAPTCHA Solving Performance by Region: Latency Analysis
Analyze how geographic region affects Captcha AI solve times — network latency, proxy location, and optimization strategies for global deployments.

Analyze how geographic region affects Captcha AI solve times — network latency, proxy location, and optimizati...

Automation Python All CAPTCHA Types
Apr 05, 2026
Reference Optimizing CaptchaAI Speed and Cost
Reduce CAPTCHA solving costs and improve speed with smart batching, caching, method selection, and architecture patterns.

Reduce CAPTCHA solving costs and improve speed with smart batching, caching, method selection, and architectur...

Automation Cloudflare Turnstile
Jan 13, 2026
Reference CAPTCHA Types Comparison Matrix 2025
Complete side-by-side comparison of every major CAPTCHA type in 2025 — re CAPTCHA, Turnstile, Gee Test, BLS, h Captcha, and image CAPTCHAs.

Complete side-by-side comparison of every major CAPTCHA type in 2025 — re CAPTCHA, Turnstile, Gee Test, BLS, h...

Web Scraping All CAPTCHA Types
Mar 31, 2026