CAPTCHA solving is now available in Nstbrowser, with support for 5 CAPTCHA types.

Learn More

🚀

Platform Proxy is live in Nstbrowser — built-in proxies from$0.4/GB.

Start Now

  • Pricing
  • Documentation
EN
Contact

© 2026 NST LABS TECH LTD. ALL RIGHTS RESERVED

Products

Anti-Detect Browser
Nstbrowser RPA
AI Agent Skills
Proxy
Cloudflare Bypass
Web Unblocker

Solutions

Cloud Fingerprint Browser
Multi-Account Management
Web Scraping & Automation
Anti-Bot Solutions
Data Isolation for Enterprise Security
Claude AI IP Checker

Resources

Pricing
Download
RPA Marketplace
Affiliate Program
Partners
Blog
Release Notes

Support

Contact

Documentation

Legal

Terms
Privacy Policy
Cookies Policy

ProductsSolutionsResourcesSupportLegal

ProductsSolutionsResources

SupportLegal

© 2026 NST LABS TECH LTD. ALL RIGHTS RESERVED

Back to Blog
CAPTCHA solver for Playwright
playwrightcaptcha-solverbrowser-automation

How to Use Nstbrowser CAPTCHA Solver with Playwright

Connect Playwright to Nstbrowser CAPTCHA Solver, configure runtime types, read page-level states, handle failures, and verify the website's final result.
Oct 20, 2026Carlos Rivera

TL;DR

  • Use Playwright’s Chromium CDP connection to attach to a Nstbrowser Profile. A browser launch or connection establishes a browser session, not CAPTCHA completion.
  • Configure CAPTCHA processing in the Dashboard or send a complete runtime captchaSolver object. For a saved Profile, runtime configuration takes precedence over Profile configuration, which takes precedence over Group configuration.
  • Read CAPTCHA progress from the documented top-level page status. Its API state names differ from the built-in plugin’s display labels.
  • Handle paused, error, and unavailable as explicit outcomes. A returned answer or an applied state does not establish that the website accepted the action.
  • Keep a separate application-level success condition and bounded timeouts. Do not wait for a CAPTCHA completion state on a page that never requires CAPTCHA.
  • Use a stopped test Profile, an API credential, and an application-owned success marker; keep connection credentials out of source files and logs.

How the Playwright integration works

Playwright controls the Nstbrowser browser context, while the built-in solver handles supported CAPTCHA processing and exposes status for your script to observe.

The connection uses the Chrome DevTools Protocol through Nstbrowser’s documented Playwright workflow. Nstbrowser’s client or Docker service provides a local endpoint on port 8848.

Playwright’s CDP connection supports Chromium-based browsers and has lower fidelity than its native protocol. Choose a Chromium-based Nstbrowser environment for this example and evaluate the Playwright features your application needs.

The intended sequence is: launch or connect to the configured Profile, navigate to your authorized page, observe CAPTCHA processing if expected, perform the application’s next action, and confirm its actual result. No CAPTCHA token extraction or manual token injection is required by the status-observation pattern below.

Prepare a stopped Profile and a controlled test page

You need an available Nstbrowser API credential, an existing stopped Profile, sufficient owning-team Credits, and an application you are authorized to test before running this integration.

A live authenticated run remains to be verified with your own test Profile. The example is a documented integration template for that validation.

Use a dedicated test Profile rather than a browser window someone is actively operating. Confirm that the Agent or Docker service is running, the plan includes CAPTCHA Solver, and the required browser kernel is available. A new runtime setting does not update an already running browser.

The sample application contract is deliberately narrow: the page displays its expected CAPTCHA on load, may require a submit action afterward, and exposes a distinct success element only after the server accepts the operation. Selectors in the environment table are values you supply for that application; they are not Nstbrowser API fields.

For action-triggered verification or multiple CAPTCHA steps, adapt the ordering and bind each observation to the current task. A terminal state left over from an earlier action must not be reused as confirmation of a later one.

Use predictable CAPTCHA testing where you own the application

Cloudflare recommends Turnstile test keys for automated application tests. Its production browser-support policy excludes automated challenge solving. Test-key outcomes do not benchmark Nstbrowser’s production solving capabilities.

Google also provides reCAPTCHA testing guidance, including v2 test keys and separate testing keys for v3. Keep test configuration separate from your production application.

Install Playwright and supply the runtime values

Install an explicit Playwright version so that your example and project lockfile identify the dependency you are using.

The code in this draft targets the available Playwright 1.62.1 package and Node.js 24 runtime. Attach to the Nstbrowser-provided browser; a separate Playwright-managed browser download is not needed for this CDP example.

bash Copy
npm init -y
npm install --save-exact [email protected]

Supply these environment values through your usual local secret-management or process configuration:

Variable Purpose
NSTBROWSER_API_KEY Your Nstbrowser API credential; keep it out of source and logs
NSTBROWSER_PROFILE_ID The existing, stopped test Profile to launch
STAGING_URL The HTTP(S) URL of your authorized test page
CAPTCHA_EXPECTED 1 for a page that creates a known CAPTCHA step; 0 to use only the normal application condition
SUCCESS_SELECTOR An element that appears only after the application confirms success
SUBMIT_SELECTOR Optional selector for the application’s post-verification submit action

For example, a test application could expose [data-test="submission-accepted"] only after its server accepts a submission. That selector is an illustrative application contract, not an element guaranteed to exist on arbitrary websites.

Launch the Profile with complete CAPTCHA configuration

Send enabled and all five type fields whenever you provide a non-empty runtime captchaSolver object.

The CAPTCHA configuration reference defines recaptchaV2, recaptchaV3, textCaptcha, awsCaptcha, and cloudflareTurnstile. At least one type must be enabled when the solver is enabled. The example enables reCAPTCHA v2, v3, and Turnstile, and explicitly disables the other two types.

For saved Profiles, omitting captchaSolver or sending an empty object inherits saved settings. A Once Browser has no Profile or Group inheritance and needs its own launch configuration. Start from a stopped environment when you change a runtime override.

The endpoint builder below uses URL.searchParams to encode the configuration once. Do not pre-encode the JSON and then encode it again. The connection URL contains your API credential, so keep the complete URL out of logs.

Credential prerequisite: the authenticated Nstbrowser handshake has not been run for this draft because an API credential and test Profile were unavailable. The supplied code was checked against the official schemas and locally checked for syntax and status-handling behavior. Validate the real connection and your application’s success condition before deployment.

Save this as run-profile.mjs:

javascript Copy
import { chromium } from 'playwright';
import { pathToFileURL } from 'node:url';

export function buildEndpoint(profileId, apiKey) {
  const endpoint = new URL(
    `/api/v2/connect/${encodeURIComponent(profileId)}`,
    'ws://127.0.0.1:8848',
  );
  endpoint.searchParams.set('x-api-key', apiKey);
  endpoint.searchParams.set('config', JSON.stringify({
    headless: false,
    captchaSolver: {
      enabled: true,
      types: {
        recaptchaV2: true,
        recaptchaV3: true,
        textCaptcha: false,
        awsCaptcha: false,
        cloudflareTurnstile: true,
      },
    },
  }));
  return endpoint.toString();
}

// This function executes in the page, so it has no outer dependencies.
export function terminalStatusInPage() {
  const raw = document.documentElement.getAttribute('data-nst-captcha-status');
  if (!raw) return false;
  let value;
  try { value = JSON.parse(raw); } catch { return false; }
  if (!value || value.schemaVersion !== 1) {
    throw new Error('Review the CAPTCHA status schema before continuing.');
  }
  if (['idle', 'solving', 'returned'].includes(value.state)) return false;
  if (!['applied', 'solved', 'paused', 'error', 'unavailable'].includes(value.state)) {
    throw new Error('Unexpected CAPTCHA state; stop and review.');
  }
  return { state: value.state, captchaType: value.captchaType ?? null };
}

export function redactError(error, apiKey) {
  let message = String(error?.message ?? error);
  for (const secret of [apiKey, apiKey ? encodeURIComponent(apiKey) : '']) {
    if (secret) message = message.split(secret).join('[redacted]');
  }
  return message.replace(/wss?:\/\/[^\s"'<>]+/g, '[CDP endpoint]');
}

export async function main() {
  const key = process.env.NSTBROWSER_API_KEY;
  const profileId = process.env.NSTBROWSER_PROFILE_ID;
  const target = process.env.STAGING_URL;
  const successSelector = process.env.SUCCESS_SELECTOR;
  const submitSelector = process.env.SUBMIT_SELECTOR;
  const expected = process.env.CAPTCHA_EXPECTED;
  if (!key || !profileId || !target || !successSelector || !['0', '1'].includes(expected)) {
    throw new Error('Set all required environment variables before running.');
  }
  const targetUrl = new URL(target);
  if (!['https:', 'http:'].includes(targetUrl.protocol)) {
    throw new Error('Use an HTTP(S) staging application you are authorized to test.');
  }

  let browser;
  let page;
  try {
    browser = await chromium.connectOverCDP(buildEndpoint(profileId, key), {
      timeout: 30_000,
    });
    const context = browser.contexts()[0];
    if (!context) throw new Error('No Profile browser context was returned.');
    page = await context.newPage();
    await page.goto(targetUrl.toString(), {
      waitUntil: 'domcontentloaded', timeout: 30_000,
    });

    if (expected === '1') {
      const handle = await page.waitForFunction(terminalStatusInPage, null, {
        polling: 250, timeout: 120_000,
      });
      let status;
      try { status = await handle.jsonValue(); } finally { await handle.dispose(); }
      console.log('CAPTCHA stage:', status.state);
      if (!['applied', 'solved'].includes(status.state)) {
        throw new Error(`CAPTCHA requires attention: ${status.state}`);
      }
    }

    if (submitSelector) await page.locator(submitSelector).click({ timeout: 30_000 });
    await page.locator(successSelector).waitFor({ state: 'visible', timeout: 30_000 });
    console.log('Application success condition observed.');
  } finally {
    if (page) await page.close().catch(() => {});
    if (browser) await browser.close();
  }
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  main().catch(error => {
    console.error(redactError(error, process.env.NSTBROWSER_API_KEY));
    process.exitCode = 1;
  });
}

After supplying the environment values, run:

bash Copy
node run-profile.mjs

The 30_000 and 120_000 timeouts are example budgets chosen for this script. They are not Nstbrowser service limits or promised solve times. The script opens one page in the Profile’s existing context rather than creating an unrelated browser context.

Try for Free >

Interpret page-level states separately from plugin labels

Use the machine-readable page states documented by Nstbrowser for automation, rather than matching the plugin’s visual text.

The page-level CAPTCHA status reference describes the data-nst-captcha-status attribute on the top-level document and the nst:captcha-status event. The event detail is a JSON string. These interfaces expose status, not a solver token, account balance, or authentication credential.

API state Meaning for this example
idle No current or recent task; do not treat it as completed verification
solving Processing is underway
returned A result returned, with application to the page not yet confirmed
applied A result was applied; perform and check the website’s next action
solved The native widget reported success; still confirm your business action
paused Processing is paused, commonly because Credits are insufficient
error Processing failed
unavailable The service or runtime is unavailable

The helper returns a bounded terminal outcome instead of waiting indefinitely for success. An absent or temporarily unreadable attribute keeps waiting until the example’s timeout; an unexpected schema or state stops the run for review.

This single-page example does not implement coordination across multiple active widgets, tabs, or concurrent account tasks. Add task-specific tracking before extending it to those workflows.

Confirm the website’s result and close the connection

Wait for an application-level success condition after CAPTCHA processing and any required form submission.

applied confirms that a result reached the page. solved reports widget success. Your application still determines whether the login, form submission, or data request completed. Choose a success selector that corresponds to that confirmed outcome rather than a generic page element that was already visible.

The example closes its page and Playwright connection in finally. Confirm the Profile’s lifecycle separately in the Nstbrowser Dashboard and stop the test environment when finished. A local script exit should not be your only check that a managed environment has stopped.

Record connection success, the relevant state, and the application outcome separately; keep API keys, connection URLs, and private page content out of the record.

Handle failures before adding retries

Stop on the first unresolved connection, configuration, CAPTCHA, or application failure before introducing a retry policy.

Failure Check
CDP connection fails Local service, port, credential, Profile ID, Chromium environment, and installed package
Saved settings appear to override your intended types Use a complete runtime object and start from a stopped Profile
Status remains absent Feature availability, selected types, environment restart, and whether a CAPTCHA is actually expected
paused The owning team’s Credits and plan availability
error or unavailable Record the state, pause the task, and use a bounded recovery or native verification route
applied occurs, but the success selector never appears Submission ordering, selector correctness, and the website’s actual acceptance

Successful solver returns are charged even when a later website action fails. Review current plan pricing before adding retries, and inspect the owning team’s CAPTCHA usage in Billing. The example deliberately contains no automatic paid retry loop.

Validate one application flow before expanding it

A verified connection, an observed CAPTCHA state, and a confirmed application result are the three separate checkpoints to establish before using this pattern in a wider job.

Start with one stopped Profile and a controlled page. Check the complete configuration, bounded failure handling, and final application condition. Once your team has verified those behaviors, adapt the workflow to additional authorized tasks while preserving their Profile and task boundaries.

The trial button opens Nstbrowser. Browser and CAPTCHA usage remain subject to the relevant plan and service charges.

Try for Free >

FAQ

Q: Does Playwright solve CAPTCHA by itself?

Playwright provides browser automation. In this integration, Nstbrowser’s built-in feature handles supported CAPTCHA processing, while Playwright observes the documented status and controls the authorized application workflow.

Q: Should I use chromium.launch or connectOverCDP?

Use chromium.connectOverCDP for this Nstbrowser Profile integration. A separate chromium.launch call starts a different browser and does not attach to the managed Profile described here.

Q: Can I use a Firefox Profile with this CDP example?

No. Playwright’s CDP connection supports Chromium-based browsers. Select an appropriate Nstbrowser environment and evaluate any browser-specific application requirements separately.

Q: Why must all five CAPTCHA type fields be present?

Nstbrowser requires a complete set of type fields when a non-empty runtime solver object is provided. Explicit true or false values make the intended policy clear and avoid malformed-override fallback behavior.

Q: Why does the script time out on a page without CAPTCHA?

A page without CAPTCHA may never produce a CAPTCHA terminal state. Set CAPTCHA_EXPECTED to 0 for the normal content flow, or build application-specific branching rather than waiting for verification on every page.

Q: Can I treat applied or solved as a completed login?

No. Those states describe result application or widget progress. Confirm the website’s own accepted login or other business result after any required submission.

Q: How should I validate the example for my application?

Run it with your own stopped test Profile and a controlled page, then confirm the connection, current CAPTCHA state, and server-confirmed application outcome separately. A syntax check or a test-key success alone does not establish successful production solver integration.

Q: How do I keep retries from creating unexpected CAPTCHA costs?

Use explicit retry limits and review the failure cause before trying again. A failed-before-return task is uncharged, but successful solver returns from retries are billable even if the website later rejects them.

More
CAPTCHA solver for Playwright
playwrightcaptcha-solverbrowser-automation
How to Use Nstbrowser CAPTCHA Solver with Playwright
Connect Playwright to Nstbrowser CAPTCHA Solver, configure runtime types, read page-level states, handle failures, and verify the website's final result.
Oct 20, 2026Carlos Rivera
how to bypass CAPTCHA while web scraping
web-scrapingcaptcha-solverbrowser-automation
How to Handle CAPTCHA While Web Scraping with a Fingerprint Browser
Handle supported CAPTCHA in authorized web scraping with Nstbrowser. Configure Profiles, verify page outcomes, limit retries, and track solver costs.
Oct 20, 2026Carlos Rivera
how to handle CAPTCHA in an antidetect browser
multi-accountcaptcha-solverbrowser-fingerprint
How to Handle CAPTCHA When Managing Multiple Accounts with a Fingerprint Browser
Learn how to handle CAPTCHA across multiple browser Profiles in Nstbrowser, with account organization, Group policies, plugin states, and billing checks.
Oct 20, 2026Carlos Rivera
Catalogue