<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DBC</title>
    <description>The latest articles on DEV Community by DBC (@dbc_81ae3384e9818e375d2d4).</description>
    <link>https://dev.to/dbc_81ae3384e9818e375d2d4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4173458%2F303d958f-c169-4f1c-a215-8442f59e25bd.png</url>
      <title>DEV Community: DBC</title>
      <link>https://dev.to/dbc_81ae3384e9818e375d2d4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dbc_81ae3384e9818e375d2d4"/>
    <language>en</language>
    <item>
      <title>Cloudflare Turnstile Solver: Wire Death By Captcha into Your Automation</title>
      <dc:creator>DBC</dc:creator>
      <pubDate>Wed, 21 Oct 2026 10:41:27 +0000</pubDate>
      <link>https://dev.to/dbc_81ae3384e9818e375d2d4/cloudflare-turnstile-solver-wire-death-by-captcha-into-your-automation-2bb0</link>
      <guid>https://dev.to/dbc_81ae3384e9818e375d2d4/cloudflare-turnstile-solver-wire-death-by-captcha-into-your-automation-2bb0</guid>
      <description>&lt;p&gt;Cloudflare Turnstile verifies visitors without showing a puzzle: no&lt;br&gt;
image grid, no checkbox to click — the widget collects signals in the&lt;br&gt;
background and hands the page a token when it trusts the session. That&lt;br&gt;
design is what makes it strong, and it is also where an automated run&lt;br&gt;
stalls: there is nothing to click, so there is nothing for a script to&lt;br&gt;
replay. This guide wires Death By Captcha (DBC) into that gap with the&lt;br&gt;
token flow: your script reads the widget's parameters from the page,&lt;br&gt;
requests a solution from the DBC API, places the token where the widget&lt;br&gt;
expects it, and the site verifies the session exactly as it would for a&lt;br&gt;
browser that passed on its own.&lt;/p&gt;

&lt;p&gt;Everything below runs against the public Turnstile demo that the&lt;br&gt;
official samples point at, so you can test the loop end to end before&lt;br&gt;
aiming it at your own target. The API calls are the ones from the&lt;br&gt;
official client examples — nothing here is invented. The shape is the&lt;br&gt;
same one the Playwright and Selenium integrations use: extract,&lt;br&gt;
request, inject, submit, verify.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the token flow
&lt;/h2&gt;

&lt;p&gt;Turnstile has one integration shape worth building on: the token. The&lt;br&gt;
challenge is evaluated on the provider's side and comes back as a&lt;br&gt;
single-submission response token; your script places it in the page and&lt;br&gt;
continues. That is what keeps the flow headless and CI-safe — nothing&lt;br&gt;
in your driver has to imitate a human pointer, because Turnstile never&lt;br&gt;
asks for one.&lt;/p&gt;

&lt;p&gt;The same shape repeats across the supported set — the payload fields&lt;br&gt;
change, the loop does not.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A DBC account — solutions are paid from your account balance, so
check the balance before decoding:
&lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python 3 or Node.js&lt;/li&gt;
&lt;li&gt;Credentials in environment variables, never in the code:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_username
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;Python (the integration guide's line):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;deathbycaptcha-official
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;deathbycaptcha-lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The solve call
&lt;/h2&gt;

&lt;p&gt;Turnstile is &lt;code&gt;type=12&lt;/code&gt; with a &lt;code&gt;turnstile_params&lt;/code&gt; payload. The payload&lt;br&gt;
carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sitekey&lt;/code&gt; — the widget's public key, read from the page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pageurl&lt;/code&gt; — the exact URL the widget is rendered on&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy&lt;/code&gt; and &lt;code&gt;proxytype&lt;/code&gt; — the same proxy your traffic uses, so the
solve context matches the submit context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aligning the proxy and the page URL with the request that submits the&lt;br&gt;
token is the single biggest reliability lever: a token solved in one&lt;br&gt;
context and submitted from another is the classic source of repeated&lt;br&gt;
retries. The official Turnstile page makes the same point first — keep&lt;br&gt;
the solve and submit flow synchronized, use bounded polling and a&lt;br&gt;
retry policy, and validate in staging before scaling volume.&lt;/p&gt;
&lt;h2&gt;
  
  
  The full flow in Python
&lt;/h2&gt;

&lt;p&gt;Adapted from the official runnable in the Python client repository&lt;br&gt;
(&lt;code&gt;examples/example.Turnstile.py&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deathbycaptcha&lt;/span&gt;

&lt;span class="n"&gt;USERNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;PAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://clifford.io/demo/cloudflare-turnstile&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SITEKEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0x4AAAAAAAGlwMzq_9z6S9Mh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deathbycaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solve_turnstile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://user:password@127.0.0.1:1234&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxytype&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sitekey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pageurl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;turnstile_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="c1"&gt;# optional pre-flight: check the balance once, not per captcha
# client.get_balance()
&lt;/span&gt;
&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;solve_turnstile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SITEKEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PAGE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no solution yet - retry with backoff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The structure is the official sample's: build the payload, pass it to&lt;br&gt;
&lt;code&gt;decode&lt;/code&gt; with &lt;code&gt;type=12&lt;/code&gt;, and read the token back from the &lt;code&gt;text&lt;/code&gt; field&lt;br&gt;
of the response. The socket client takes the same &lt;code&gt;decode&lt;/code&gt; call if you&lt;br&gt;
prefer the persistent transport.&lt;/p&gt;
&lt;h2&gt;
  
  
  The same flow in Node.js
&lt;/h2&gt;

&lt;p&gt;Adapted from the official runnable in the Node.js client repository&lt;br&gt;
(&lt;code&gt;examples/example.Turnstile.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deathbycaptcha-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USERNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://clifford.io/demo/cloudflare-turnstile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SITEKEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x4AAAAAAAGlwMzq_9z6S9Mh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;dbc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;solveTurnstile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageurl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;turnstile_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://username:password@proxy.example:3128&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;proxytype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HTTP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pageurl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pageurl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;turnstile_params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;turnstile_params&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;captcha&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;captcha&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;captcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;captcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no solution yet - retry with backoff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;solveTurnstile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SITEKEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PAGE_URL&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Node.js client takes the same two fields under an &lt;code&gt;extra&lt;/code&gt; object,&lt;br&gt;
and the token comes back on &lt;code&gt;captcha.text&lt;/code&gt;. It is the same call shape&lt;br&gt;
the Python client uses, so the two stay in lockstep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Placing the token in the page
&lt;/h2&gt;

&lt;p&gt;The token is not the end of the job — it has to land where the widget&lt;br&gt;
expects it. Turnstile exposes the solved response through a hidden form&lt;br&gt;
field named &lt;code&gt;cf-turnstile-response&lt;/code&gt; and, on pages that read the token&lt;br&gt;
in JavaScript, through the widget's own success callback. Your driver&lt;br&gt;
does one of two things with the solved token:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pages that submit a form: write the token into the
&lt;code&gt;cf-turnstile-response&lt;/code&gt; field so the normal submit carries it.&lt;/li&gt;
&lt;li&gt;Pages that read the token from JavaScript: pass the token into the
widget's success callback so the page continues on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep this step synchronized with the solve call: the same proxy, the&lt;br&gt;
same page URL, and no long gap between the solve finishing and the&lt;br&gt;
token being submitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Turnstile
&lt;/h2&gt;

&lt;p&gt;The same loop covers the rest of the supported set. reCAPTCHA v3,&lt;br&gt;
GeeTest, DataDome, plus image and text captchas follow their own&lt;br&gt;
documented payloads — each CAPTCHA type is routed to a model&lt;br&gt;
specialized for that type. The official Python client ships a runnable&lt;br&gt;
sample per type under &lt;code&gt;examples/&lt;/code&gt;, and the Node.js client mirrors&lt;br&gt;
them.&lt;/p&gt;

&lt;p&gt;Both clients default to the encrypted HTTPS transport and also ship a&lt;br&gt;
socket transport for high-throughput production runs; the method names&lt;br&gt;
stay the same, so moving between them later is a constructor change,&lt;br&gt;
not a rewrite.&lt;/p&gt;

&lt;p&gt;On the library side, official clients cover Python, Node.js, C#, Java,&lt;br&gt;
.NET, Go, C, C++ and Perl, and the browser extensions for Chrome/Brave&lt;br&gt;
and Firefox cover the no-code path for manual sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fitting it into a bigger run
&lt;/h2&gt;

&lt;p&gt;The official samples are built for pipelines, and the Turnstile page's&lt;br&gt;
rollout guidance fits the same habits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Align proxy and verification context to reduce mismatches.&lt;/li&gt;
&lt;li&gt;Use bounded polling and a retry policy for predictable runs.&lt;/li&gt;
&lt;li&gt;Validate in staging before scaling request volume.&lt;/li&gt;
&lt;li&gt;Keep one code path for local and CI — only flags change, never the
flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Notes that save runs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Credentials stay in environment variables in both official samples.&lt;/li&gt;
&lt;li&gt;The balance call is a pre-flight, not part of the solve loop: check
it once at pipeline start, not per captcha.&lt;/li&gt;
&lt;li&gt;The payload's &lt;code&gt;pageurl&lt;/code&gt; must match the page the token is submitted
from — that is the context sync the official page names first.&lt;/li&gt;
&lt;li&gt;End with the honest branch: no solution -&amp;gt; retry with backoff. Wire
that branch before production.&lt;/li&gt;
&lt;li&gt;Fail loudly on timeouts instead of letting a stalled challenge hang
the pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docs and sign-up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API reference and client links: &lt;a href="https://deathbycaptcha.com/api" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Turnstile solver page:
&lt;a href="https://deathbycaptcha.com/turnstile-solver" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/turnstile-solver&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python API integration guide:
&lt;a href="https://deathbycaptcha.com/python-captcha-api" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/python-captcha-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Balance and pricing: &lt;a href="https://deathbycaptcha.com/user-pay" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/user-pay&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create an account: &lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>cloudflare</category>
      <category>turnstile</category>
    </item>
    <item>
      <title>Selenium Captcha Solver: Wire Death By Captcha into Your Test Runs</title>
      <dc:creator>DBC</dc:creator>
      <pubDate>Fri, 16 Oct 2026 11:54:38 +0000</pubDate>
      <link>https://dev.to/dbc_81ae3384e9818e375d2d4/selenium-captcha-solver-wire-death-by-captcha-into-your-test-runs-2o9d</link>
      <guid>https://dev.to/dbc_81ae3384e9818e375d2d4/selenium-captcha-solver-wire-death-by-captcha-into-your-test-runs-2o9d</guid>
      <description>&lt;p&gt;Selenium turns a browser script into a test that acts like a&lt;br&gt;
user: it clicks, types, waits, asserts. A captcha challenge is&lt;br&gt;
where that illusion breaks — the run stalls on a widget that no&lt;br&gt;
amount of click emulation reliably dismisses. This quickstart&lt;br&gt;
wires Death By Captcha (DBC) into a Selenium script with one&lt;br&gt;
repeatable pattern: the script reads the challenge parameters&lt;br&gt;
from the page, requests a solution from the DBC API, injects the&lt;br&gt;
token back into the page, and continues — the site verifies it&lt;br&gt;
exactly as if the widget had been solved in a real browser.&lt;/p&gt;

&lt;p&gt;Everything below runs against Google's own public reCAPTCHA demo,&lt;br&gt;
so you can test the whole loop end to end before pointing it at&lt;br&gt;
your own target. The calls are the ones from the official&lt;br&gt;
samples — the Selenium integration page and the runnable&lt;br&gt;
examples that ship in the Python and Node.js client&lt;br&gt;
repositories — nothing here is invented. The shape is the same&lt;br&gt;
one the Playwright integration uses: extract, request, inject,&lt;br&gt;
submit, assert.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the token flow
&lt;/h2&gt;

&lt;p&gt;reCAPTCHA v2 has two integration shapes: replaying the interactive&lt;br&gt;
challenge inside your browser context, or the token flow used here.&lt;br&gt;
The token flow solves the challenge on the provider's side and returns&lt;br&gt;
a response token that is valid for one submission; your script injects&lt;br&gt;
it and moves on. That is what makes it work headless and inside CI:&lt;br&gt;
nothing in your driver has to mimic a human pointer, and the page&lt;br&gt;
sees a normal solved widget.&lt;/p&gt;

&lt;p&gt;The same shape repeats across the supported set — the payload fields&lt;br&gt;
change, the loop does not.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A DBC account — solutions are paid from your account balance, so
check the balance before decoding:
&lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python 3 or Node.js, plus Selenium and Firefox or Chrome
(Selenium 4 resolves the driver on its own, so the browser is
the only extra install)&lt;/li&gt;
&lt;li&gt;Credentials in environment variables, never in the code:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_username
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;Python (the integration page's line):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;selenium deathbycaptcha-official
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;selenium-webdriver deathbycaptcha-lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The full flow in Python
&lt;/h2&gt;

&lt;p&gt;Adapted from the official runnable in the Python client&lt;br&gt;
repository (&lt;code&gt;examples/deathbycaptcha-python-selenium&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deathbycaptcha&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;selenium.webdriver.support&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;expected_conditions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;EC&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;selenium.webdriver.support.wait&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WebDriverWait&lt;/span&gt;

&lt;span class="n"&gt;USERNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DEMO_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.google.com/recaptcha/api2/demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solve_captcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deathbycaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SocketClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# optional pre-flight, both official samples do it:
&lt;/span&gt;    &lt;span class="c1"&gt;# client.get_balance()
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_page_load_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEMO_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. extract the challenge parameters from the page
&lt;/span&gt;    &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WebDriverWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;EC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presence_of_element_located&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recaptcha-demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="n"&gt;sitekey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data-sitekey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. request the solution token from DBC (type 4 = reCAPTCHA v2)
&lt;/span&gt;    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;solve_captcha&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;googlekey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pageurl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DEMO_URL&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no solution yet - retry with backoff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. inject the token back into the page
&lt;/span&gt;    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document.getElementById(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;g-recaptcha-response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.value = arguments[0]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. submit and check the success element
&lt;/span&gt;    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recaptcha-demo-submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLASS_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recaptcha-success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details lifted straight from the official runnable: the&lt;br&gt;
explicit &lt;code&gt;WebDriverWait&lt;/code&gt; instead of blind sleeps for finding the&lt;br&gt;
widget, and the page-load timeout so a stalled navigation fails&lt;br&gt;
loudly instead of hanging the suite. The full script also switches&lt;br&gt;
Firefox/Chrome and headless mode from environment variables.&lt;/p&gt;
&lt;h2&gt;
  
  
  The same flow in Node.js
&lt;/h2&gt;

&lt;p&gt;Adapted from the official runnable in the Node.js client&lt;br&gt;
repository (&lt;code&gt;examples/selenium/recaptcha_v2_selenium.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;By&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selenium-webdriver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deathbycaptcha-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USERNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEMO_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.google.com/recaptcha/api2/demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no solution yet - retry with backoff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firefox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEMO_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. extract the challenge parameters from the page&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementLocated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recaptcha-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sitekey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDomAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-sitekey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. request the solution token from DBC (type 4 = reCAPTCHA v2)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;token_params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;googlekey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pageurl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEMO_URL&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. inject the token back into the page&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
      const token = arguments[0];
      const textarea = document.getElementById('g-recaptcha-response');
      textarea.style.display = 'block';
      textarea.value = token;
      textarea.innerHTML = token;
      textarea.dispatchEvent(new Event('input', { bubbles: true }));
      textarea.dispatchEvent(new Event('change', { bubbles: true }));
      if (window.___grecaptcha_cfg &amp;amp;&amp;amp; window.___grecaptcha_cfg.clients) {
        const clients = window.___grecaptcha_cfg.clients;
        for (const clientKey of Object.keys(clients)) {
          const item = clients[clientKey];
          for (const key of Object.keys(item)) {
            const entry = item[key];
            if (entry &amp;amp;&amp;amp; typeof entry.callback === 'function') {
              entry.callback(token);
              return true;
            }
            if (entry &amp;amp;&amp;amp; entry.W &amp;amp;&amp;amp; typeof entry.W.callback === 'function') {
              entry.W.callback(token);
              return true;
            }
          }
        }
      }
      return true;
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. submit and wait for the success element&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recaptcha-demo-submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementLocated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;className&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recaptcha-success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page-side steps are identical to the Python version; the&lt;br&gt;
injection block goes one step further and fires the widget's own&lt;br&gt;
callback from the reCAPTCHA config tree — that is what wakes the&lt;br&gt;
page up when setting the textarea alone is not enough. The full&lt;br&gt;
runnable wraps the same logic in an exported function with the&lt;br&gt;
browser and timeouts read from environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond reCAPTCHA v2
&lt;/h2&gt;

&lt;p&gt;The same loop covers the rest of the supported set. Turnstile is the&lt;br&gt;
same call with a different type and payload name — &lt;code&gt;type=12&lt;/code&gt; with a&lt;br&gt;
&lt;code&gt;turnstile_params&lt;/code&gt; payload carrying &lt;code&gt;sitekey&lt;/code&gt; and &lt;code&gt;pageurl&lt;/code&gt; — and&lt;br&gt;
reCAPTCHA v3, GeeTest, DataDome, plus image and text captchas follow&lt;br&gt;
their own documented payloads: each CAPTCHA type is routed to a model&lt;br&gt;
specialized for that type. The official Python client ships a runnable&lt;br&gt;
sample per type under &lt;code&gt;examples/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both clients default to the encrypted HTTPS transport and also ship a&lt;br&gt;
socket transport for high-throughput production runs; the method names&lt;br&gt;
stay the same, so moving between them later is a constructor change,&lt;br&gt;
not a rewrite. The Python flow above already runs on the socket&lt;br&gt;
client — same &lt;code&gt;decode&lt;/code&gt; call the HTTPS transport serves.&lt;/p&gt;

&lt;p&gt;On the library side, official clients cover Python, Node.js, C#, Java,&lt;br&gt;
.NET, Go, C, C++ and Perl, and the browser extensions for Chrome/Brave&lt;br&gt;
and Firefox cover the no-code path for manual sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fitting it into a bigger run
&lt;/h2&gt;

&lt;p&gt;The official runnables are built for pipelines: browser choice,&lt;br&gt;
headless mode and wait timeouts all come from environment&lt;br&gt;
variables, and the Node.js sample extends its wait when it&lt;br&gt;
detects CI so slow runners do not race the page. Keep three&lt;br&gt;
habits from them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One code path for local and CI — only flags change, never the
flow. Inconsistent challenge handling across environments is
how green suites start failing on runners.&lt;/li&gt;
&lt;li&gt;Explicit waits around the widget and the success element; a
sleep is only safe where the official sample uses it as a
short demo pause, not as synchronization.&lt;/li&gt;
&lt;li&gt;Fail loudly on timeouts (page-load timeout, element waits)
instead of letting a stalled challenge hang the pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Notes that save runs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Credentials stay in environment variables in both official
samples — the Node.js one refuses to start with the literal
placeholder values still in place.&lt;/li&gt;
&lt;li&gt;The balance call is a pre-flight, not part of the solve loop:
check it once at pipeline start, not per captcha.&lt;/li&gt;
&lt;li&gt;Sitekey extraction has a fallback in the official Python
script (attribute read, then a script-side read) because
widgets render differently across drivers — keep both.&lt;/li&gt;
&lt;li&gt;Both samples end with the same honest branch: no solution -&amp;gt;
retry with backoff. Wire that branch before production; a
retry policy is what separates flaky solves causing
intermittent test failures from a pipeline that recovers.&lt;/li&gt;
&lt;li&gt;Treat a missing success element as a first-class outcome
(the Python sample catches it and reports it) — silent
passes are how broken flows ship.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docs and sign-up
&lt;/h2&gt;

&lt;p&gt;The same shape applies to the other runners: the integration&lt;br&gt;
pages for Playwright and Puppeteer walk the same&lt;br&gt;
request-and-inject loop, and the per-type examples document&lt;br&gt;
every payload field the clients accept.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API reference and client links: &lt;a href="https://deathbycaptcha.com/api" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Selenium integration page:
&lt;a href="https://deathbycaptcha.com/selenium-captcha-solver" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/selenium-captcha-solver&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Balance and pricing: &lt;a href="https://deathbycaptcha.com/user-pay" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/user-pay&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create an account: &lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>selenium</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Playwright Captcha Solver: Wire Death By Captcha into Your Automation</title>
      <dc:creator>DBC</dc:creator>
      <pubDate>Wed, 14 Oct 2026 11:49:53 +0000</pubDate>
      <link>https://dev.to/dbc_81ae3384e9818e375d2d4/playwright-captcha-solver-wire-death-by-captcha-into-your-automation-56bd</link>
      <guid>https://dev.to/dbc_81ae3384e9818e375d2d4/playwright-captcha-solver-wire-death-by-captcha-into-your-automation-56bd</guid>
      <description>&lt;p&gt;Playwright makes browser automation fast — until a captcha challenge&lt;br&gt;
stops the run mid-flow. This quickstart wires Death By Captcha (DBC)&lt;br&gt;
into a Playwright script with one repeatable pattern: the script reads&lt;br&gt;
the challenge parameters from the page, requests a solution from the&lt;br&gt;
DBC API, injects the token back into the page, and continues — the&lt;br&gt;
site verifies it exactly as if the widget had been solved in a real&lt;br&gt;
browser. No click emulation, no brittle waits on challenge dialogs.&lt;/p&gt;

&lt;p&gt;Everything below runs against Google's own public reCAPTCHA demo, so&lt;br&gt;
you can test the whole loop end to end before pointing it at your own&lt;br&gt;
target. The calls are the ones from the official runnable examples —&lt;br&gt;
nothing here is invented. Beyond the client's few methods (balance,&lt;br&gt;
upload, poll) there is no extra SDK surface to learn: the whole&lt;br&gt;
integration is one request-and-inject cycle you can read in a single&lt;br&gt;
sitting and reuse everywhere the same challenge type shows up.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the token flow
&lt;/h2&gt;

&lt;p&gt;reCAPTCHA v2 has two integration shapes: replaying the interactive&lt;br&gt;
challenge inside your browser context, or the token flow used here.&lt;br&gt;
The token flow solves the challenge on the provider's side and returns&lt;br&gt;
a response token that is valid for one submission; your script injects&lt;br&gt;
it and moves on. That is what makes it work headless and inside CI:&lt;br&gt;
nothing in your browser has to mimic a human pointer, and the page&lt;br&gt;
sees a normal solved widget.&lt;/p&gt;

&lt;p&gt;The same shape repeats across the supported set — the payload fields&lt;br&gt;
change, the loop does not.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A DBC account — solutions are paid from your account balance, so
check the balance before decoding:
&lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python 3 or Node.js, plus Playwright&lt;/li&gt;
&lt;li&gt;Credentials in environment variables, never in the code:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_username
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;deathbycaptcha-official playwright
playwright &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;deathbycaptcha-lib playwright
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The full flow in Python
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deathbycaptcha&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;playwright.sync_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sync_playwright&lt;/span&gt;

&lt;span class="n"&gt;DEMO_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.google.com/recaptcha/api2/demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deathbycaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solve_recaptcha_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Request a reCAPTCHA v2 token (API type=4), poll until solved.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_balance&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no balance - top up before decoding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;token_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;googlekey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pageurl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;captcha&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;deadline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_captcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no solution; retry with backoff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;sync_playwright&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEMO_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. read the challenge parameters from the page
&lt;/span&gt;    &lt;span class="n"&gt;sitekey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#recaptcha-demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data-sitekey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. request the solution token from DBC
&lt;/span&gt;    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;solve_recaptcha_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEMO_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. inject the token and trigger the page's own callback
&lt;/span&gt;    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;(t) =&amp;gt; {
            const el = document.getElementById(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;g-recaptcha-response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;);
            if (!el) return;
            el.style.display = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;block&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;;
            el.value = t;
            el.dispatchEvent(new Event(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, { bubbles: true }));
            el.dispatchEvent(new Event(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;change&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, { bubbles: true }));
            const cfg = window.___grecaptcha_cfg;
            if (!cfg || !cfg.clients) return;
            for (const k of Object.keys(cfg.clients)) {
                const c = cfg.clients[k];
                for (const key of Object.keys(c)) {
                    const item = c[key];
                    if (item &amp;amp;&amp;amp; typeof item.callback === &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)
                        return item.callback(t);
                    if (item &amp;amp;&amp;amp; item.W &amp;amp;&amp;amp;
                        typeof item.W.callback === &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)
                        return item.W.callback(t);
                }
            }
        }&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. submit and wait for the page to report success
&lt;/span&gt;    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#recaptcha-demo-submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for_selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.recaptcha-success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;solved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python playwright_dbc_quickstart.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the token is accepted, the script prints &lt;code&gt;solved&lt;/code&gt; and exits 0. If&lt;br&gt;
the challenge is not solved within the timeout it raises — a broken&lt;br&gt;
integration fails loudly instead of hanging your pipeline. That&lt;br&gt;
failure path is the runnable test: wire the script into CI as-is, or&lt;br&gt;
drop the last three lines into a test runner and assert on the&lt;br&gt;
success selector like any other page state.&lt;/p&gt;

&lt;p&gt;What each step does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;get_balance()&lt;/code&gt; — confirm the account can pay for the job before
submitting anything.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;upload(type=4, ...)&lt;/code&gt; — type 4 is the reCAPTCHA v2 token API. The
&lt;code&gt;googlekey&lt;/code&gt; (the widget's site key) and &lt;code&gt;pageurl&lt;/code&gt; (the exact URL
where the challenge loads, path included) identify the challenge;
the client polls &lt;code&gt;get_captcha()&lt;/code&gt; until the token text arrives.&lt;/li&gt;
&lt;li&gt;The token goes into the page's hidden response field and the
page's own reCAPTCHA callback fires — from the site's point of
view the widget was solved normally.&lt;/li&gt;
&lt;li&gt;The submit click plus the success selector close the loop.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The same flow in Node.js
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deathbycaptcha-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DBC_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DBC_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;solveRecaptchaV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;token_params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;googlekey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sitekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pageurl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pageUrl&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no solution yet - retry with backoff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page-side steps — extract the sitekey, request the token, inject&lt;br&gt;
it, trigger the callback — are identical to the Python version. The&lt;br&gt;
official sample also checks the balance first, and the full runnable&lt;br&gt;
script ships in the official Node.js client repository under&lt;br&gt;
&lt;code&gt;examples/playwright&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond reCAPTCHA v2
&lt;/h2&gt;

&lt;p&gt;The same loop covers the rest of the supported set. Turnstile is the&lt;br&gt;
same call with a different type and payload name — &lt;code&gt;type=12&lt;/code&gt; with a&lt;br&gt;
&lt;code&gt;turnstile_params&lt;/code&gt; payload carrying &lt;code&gt;sitekey&lt;/code&gt; and &lt;code&gt;pageurl&lt;/code&gt; — and&lt;br&gt;
reCAPTCHA v3, GeeTest, DataDome, plus image and text captchas follow&lt;br&gt;
their own documented payloads: each CAPTCHA type is routed to a model&lt;br&gt;
specialized for that type. The official Python client ships a runnable&lt;br&gt;
sample per type under &lt;code&gt;examples/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both clients default to the encrypted HTTPS transport and also ship a&lt;br&gt;
socket transport for high-throughput production runs; the method names&lt;br&gt;
stay the same, so moving between them later is a constructor change,&lt;br&gt;
not a rewrite.&lt;/p&gt;

&lt;p&gt;On the library side, official clients cover Python, Node.js, C#, Java,&lt;br&gt;
.NET, Go, C, C++ and Perl, and the browser extensions for Chrome/Brave&lt;br&gt;
and Firefox cover the no-code path for manual sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fitting it into a bigger run
&lt;/h2&gt;

&lt;p&gt;Nothing in the script has to run standalone. In a real scraper or test&lt;br&gt;
suite the pattern sits next to the action that gets blocked: navigate,&lt;br&gt;
detect the challenge widget on the page, call the solve step, inject,&lt;br&gt;
continue. Because the token is requested only when a challenge is&lt;br&gt;
actually present, unblocked runs submit no jobs at all, and the&lt;br&gt;
balance check doubles as a first failure gate for scheduled jobs.&lt;br&gt;
Keep the solve function in one shared module and every Playwright&lt;br&gt;
entrypoint in the project can call it without copy-paste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes that save runs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep the solve path and the submit path on the same network. The
token is verified from the IP that submits it, and a mismatch
between that address and the context the challenge was solved in is
the usual cause of rejected tokens. If your automation already goes
through a proxy, pass it in the same params payload (&lt;code&gt;proxy&lt;/code&gt; +
&lt;code&gt;proxytype&lt;/code&gt;) so both hops align.&lt;/li&gt;
&lt;li&gt;Retry with backoff on an empty result. "No solution yet" is
transient by design — the official examples retry instead of
failing immediately.&lt;/li&gt;
&lt;li&gt;Set explicit timeouts at every hop: navigation, upload, polling,
page waits. Silent stalls are how one flaky challenge turns into a
hung pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docs and sign-up
&lt;/h2&gt;

&lt;p&gt;The same shape applies to the other runners: the integration pages&lt;br&gt;
for Selenium and Puppeteer walk the same request-and-inject loop, and&lt;br&gt;
the per-type FAQ documents every payload field the clients accept.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API reference and client links: &lt;a href="https://deathbycaptcha.com/api" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Playwright integration page:
&lt;a href="https://deathbycaptcha.com/playwright-captcha-solver" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/playwright-captcha-solver&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Balance and pricing: &lt;a href="https://deathbycaptcha.com/user-pay" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/user-pay&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create an account: &lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;https://deathbycaptcha.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>Best Captcha Solvers 2026: Comparison</title>
      <dc:creator>DBC</dc:creator>
      <pubDate>Fri, 09 Oct 2026 14:18:53 +0000</pubDate>
      <link>https://dev.to/dbc_81ae3384e9818e375d2d4/best-captcha-solvers-2026-comparison-1c88</link>
      <guid>https://dev.to/dbc_81ae3384e9818e375d2d4/best-captcha-solvers-2026-comparison-1c88</guid>
      <description>&lt;p&gt;If you are picking a captcha solving service for automation, web&lt;br&gt;
scraping, or browser testing in 2026, the shortlist usually looks&lt;br&gt;
the same: a handful of long-running APIs that solve reCAPTCHA,&lt;br&gt;
Cloudflare Turnstile, GeeTest, and image captchas and return a&lt;br&gt;
token or text answer your script can use. This article is a real&lt;br&gt;
comparison of the five services that show up in those shortlists:&lt;br&gt;
shared criteria, a side-by-side matrix built from each provider's&lt;br&gt;
public documentation, and a per-provider analysis — so you can&lt;br&gt;
re-rank the table against your own priorities.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we compared
&lt;/h2&gt;

&lt;p&gt;Six criteria, applied to every provider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modern captcha type coverage&lt;/strong&gt; — reCAPTCHA (v2/v3/Enterprise),
Cloudflare Turnstile, GeeTest, and image captchas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Official client libraries&lt;/strong&gt; — languages each provider ships
officially, not community wrappers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API and documentation&lt;/strong&gt; — a clear HTTP flow (send the
challenge, receive the solution) with real docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing model&lt;/strong&gt; — pay-as-you-go with published rates, plus
what our own testing showed about advertised vs charged
amounts (see the matrix note ¶).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration fit&lt;/strong&gt; — Selenium / Playwright / Puppeteer
workflows and browser extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability&lt;/strong&gt; — what each service publishes about uptime
(status page, claims) versus what a real solve does at your
hour; the DBC API accepts requests 24/7.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Method: every capability cell was checked against the provider's&lt;br&gt;
own public docs on 2026-10-09; the pricing (¶) and availability (†)&lt;br&gt;
notes are our own testing. Features move fast — re-check before you buy.&lt;br&gt;
Scope: only the four modern types above; legacy challenge types&lt;br&gt;
are out of scope. Ranking note: this is DBC's own disclosed&lt;br&gt;
comparison, DBC is weighted first on integration breadth, and the&lt;br&gt;
matrix is here so you can disagree with that weighting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side-by-side matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Types*&lt;/th&gt;
&lt;th&gt;Clients&lt;/th&gt;
&lt;th&gt;Extension&lt;/th&gt;
&lt;th&gt;Availability&lt;/th&gt;
&lt;th&gt;Pricing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Death By Captcha&lt;/td&gt;
&lt;td&gt;4 of 4&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Chrome, FF&lt;/td&gt;
&lt;td&gt;24/7&lt;/td&gt;
&lt;td&gt;deathbycaptcha.com/user-pay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2Captcha&lt;/td&gt;
&lt;td&gt;4 of 4&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Chrome&lt;/td&gt;
&lt;td&gt;verify†&lt;/td&gt;
&lt;td&gt;not clear¶&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anti-Captcha&lt;/td&gt;
&lt;td&gt;4 of 4&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;verify†&lt;/td&gt;
&lt;td&gt;rate page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CapSolver&lt;/td&gt;
&lt;td&gt;4 of 4&lt;/td&gt;
&lt;td&gt;SDKs&lt;/td&gt;
&lt;td&gt;Chrome, FF&lt;/td&gt;
&lt;td&gt;verify†&lt;/td&gt;
&lt;td&gt;rate page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CapMonster Cloud&lt;/td&gt;
&lt;td&gt;4 of 4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Chrome, FF&lt;/td&gt;
&lt;td&gt;verify†&lt;/td&gt;
&lt;td&gt;rate page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;* Types = the four compared modern types — reCAPTCHA
(v2/v3/Enterprise), Cloudflare Turnstile, GeeTest, and image
captchas. All five cover 4 of 4, verified in each provider's
public docs on 2026-10-09. Parity on types is the finding here.&lt;/li&gt;
&lt;li&gt;Clients = official client languages published by each provider:
DBC 9 (Python, Node.js, C#, Java, .NET, Go, C, C++, Perl);
2Captcha 7 (Python, Java, C#, C++, JavaScript, Ruby, PHP);
Anti-Captcha 10 (Python, Node.js, Go, PHP, Java, Kotlin, C#,
C++, Rust, Ruby); CapSolver ships SDKs plus community libraries
without one fixed language list; CapMonster Cloud 5 (C#,
Python, JS, Go, PHP).&lt;/li&gt;
&lt;li&gt;FF = Firefox; the DBC extension also runs on Brave.&lt;/li&gt;
&lt;li&gt;† Availability: the DBC API accepts requests 24/7. All four
others publish a status page and uptime-style claims (checked
2026-10-09 — e.g. "99.9% uptime" and "uptime since 2007" appear
in their marketing). Our own testing (October 2026) saw the
opposite: a status page showed the service operational while a
real solve request failed. Treat any "operational" badge as a
starting point, not proof — verify with a live solve at your
target hour.&lt;/li&gt;
&lt;li&gt;¶ Pricing: all five publish pay-as-you-go rates. With 2Captcha,
our own testing (October 2026) hit a mismatch between the rate
advertised on their site and the amount actually charged — we
mark them "not clear": verify for yourself with a small run
before committing. We quote no figures here; read current rates
on each provider's rate page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Death By Captcha (DBC)
&lt;/h2&gt;

&lt;p&gt;Death By Captcha (DBC) is a reliable captcha solver API for&lt;br&gt;
automation, web scraping, and browser workflows, with official&lt;br&gt;
client libraries, browser extensions, and support for modern&lt;br&gt;
captcha types. Against the criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Types:&lt;/strong&gt; all four covered — each CAPTCHA type is routed to a
model specialized for that type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clients:&lt;/strong&gt; nine official ones (Python, Node.js, C#, Java, .NET,
Go, C, C++, Perl), covering both application stacks and systems
languages (C, C++, Perl) in one official set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extension:&lt;/strong&gt; Chrome and Firefox stores; the Chrome build also
runs on Brave.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability:&lt;/strong&gt; the API accepts requests 24/7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workflow:&lt;/strong&gt; official examples for Selenium, Playwright, and
Puppeteer — send the challenge (type, page URL, sitekey), get the
solution back, inject the token into your run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs and pricing:&lt;/strong&gt; public API docs, public rate page,
pay-as-you-go.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with the &lt;a href="https://deathbycaptcha.com/api" rel="noopener noreferrer"&gt;API docs&lt;/a&gt;, check&lt;br&gt;
the &lt;a href="https://deathbycaptcha.com/user-pay" rel="noopener noreferrer"&gt;rate page&lt;/a&gt; for pricing,&lt;br&gt;
and &lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;create an account&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 2Captcha
&lt;/h2&gt;

&lt;p&gt;A long-running service with a wide HTTP API and seven official&lt;br&gt;
client libraries (Python, Java, C#, C++, JavaScript, Ruby, PHP).&lt;br&gt;
All four compared types are covered, the official extension lives&lt;br&gt;
in the Chrome store, and the docs ship ready-made code examples&lt;br&gt;
for scraping scripts. Trade-off vs the rest of this table:&lt;br&gt;
Firefox users are not covered by an official extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Anti-Captcha
&lt;/h2&gt;

&lt;p&gt;The most developer-facing of the five: a documentation-first API&lt;br&gt;
with an apidoc, tutorials, and the widest official client list&lt;br&gt;
here — ten languages (Python, Node.js, Go, PHP, Java, Kotlin, C#,&lt;br&gt;
C++, Rust, Ruby). All four compared types are covered. Trade-off:&lt;br&gt;
it is API-only — no browser extension appears on their public&lt;br&gt;
surface, so everything runs through your own code.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. CapSolver
&lt;/h2&gt;

&lt;p&gt;A newer-generation, task-based API covering all four compared&lt;br&gt;
types plus adjacent protections (AWS WAF, Cloudflare challenge).&lt;br&gt;
Its weight sits in integration: SDKs with community libraries,&lt;br&gt;
hooks for Selenium, Puppeteer, Playwright and n8n, an official&lt;br&gt;
Chrome/Firefox extension, and 2026-era agent integrations (MCP&lt;br&gt;
and agent tooling). Docs are organized as guides per captcha type.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. CapMonster Cloud
&lt;/h2&gt;

&lt;p&gt;A straightforward JSON request/response API with five official&lt;br&gt;
SDKs (C#, Python, JS, Go, PHP) and official Chrome and Firefox&lt;br&gt;
extensions. All four compared types are covered. It is the&lt;br&gt;
simplest of the five to start with if one of those five languages&lt;br&gt;
fits your stack; teams outside them lean on community libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start from the matrix: if a provider misses a type you need or
your language, it is out.&lt;/li&gt;
&lt;li&gt;Check the official client for your stack — Python and Node.js
cover most teams, but on Go, .NET, C or Rust the lists diverge
fast.&lt;/li&gt;
&lt;li&gt;Read the docs before signing up: the send-solution flow has to
fit your run loop cleanly.&lt;/li&gt;
&lt;li&gt;Test on your own targets first: one integration, small batches,
measure solve quality against your real sites.&lt;/li&gt;
&lt;li&gt;Compare pricing on each provider's rate page — figures change,
and verify the actual charge with a small run: at least one
provider here billed us differently than advertised.&lt;/li&gt;
&lt;li&gt;Verify availability with a live solve at your own target hour:
in our testing, a status badge showed "operational" while a real
request failed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;On the four modern types the market treats as table stakes, all&lt;br&gt;
five services are effectively at parity — so the real decision is&lt;br&gt;
about clients, docs, extensions, and workflow fit, which is what&lt;br&gt;
the matrix and the notes above spell out. Our own weighting puts&lt;br&gt;
Death By Captcha (DBC) first for integration breadth: nine&lt;br&gt;
official clients, extensions for both browser families, 24/7 API&lt;br&gt;
availability, official Selenium/Playwright/Puppeteer examples,&lt;br&gt;
and typed-model routing behind one API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://deathbycaptcha.com/api" rel="noopener noreferrer"&gt;API docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deathbycaptcha.com/user-pay" rel="noopener noreferrer"&gt;Rate page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deathbycaptcha.com/register" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webscraping</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
