How to Integrate CapSolver with Playwright | Complete Guide 2025

Ethan Collins
Pattern Recognition Specialist
04-Jun-2025

What is Playwright?
Playwright is a modern browser automation testing framework developed by Microsoft. It supports automation for Chromium, Firefox, and WebKit (which correspond to Chrome, Firefox, and Safari). It offers a powerful API for browser control, element selection, form interaction, network interception, and more—making it ideal for tasks that require deep interaction with web pages.
Core Features of Playwright
Any browser, Any platform, One API
- Cross-browser: Playwright supports all modern rendering engines, including Chromium, WebKit, and Firefox.
- Cross-platform: Run tests on Windows, Linux, and macOS—locally or in CI—headless or headed.
- Cross-language: Use the Playwright API with TypeScript, JavaScript, Python, .NET, or Java.
- Test Mobile Web: Natively emulate Google Chrome for Android and Mobile Safari. The same rendering engine runs on your Desktop and in the Cloud.
Typical Use Cases
- Scraping dynamic content: Extract data rendered via JavaScript.
- Handling complex interactions: Useful for pages that require login or multi-step workflows to access data.
- Extracting data from SPA apps: Crawl pages built with frameworks like Vue or React.
- Automated testing: Validate page functionality while collecting data.
- Headless mode automation: Perform all actions without a GUI, suitable for server environments.
Basic Usage of Playwright
Using Playwright in Node.js:
bash
npm i playwright
npx playwright install # Install all browsers (Chromium, Firefox, WebKit)
Example: Get all blog titles from CapSolver
In the example below, We use Playwirght to navigate to the CapSolver blog and grab all the <h5>
blog post titles from the page

javascript
const { chromium } = require('playwright');
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
});
const [page] = context.pages();
await page.goto('https://www.capsolver.com/blog/All');
const h5Titles = await page.evaluate(() => {
const headings = Array.from(document.querySelectorAll('h5'));
return headings.map(heading => heading.textContent.trim());
});
console.log(h5Titles);
await context.close();
})();
How to Integrate CapSolver Extension with Playwright
Playwright is powerful enough to load browser extensions just like a regular browser.
- Download and extract the latest CapSolver extension ZIP from the official GitHub
- Specify the extension path in the Playwright launch arguments using
--disable-extensions-except
and--load-extension
.
javascript
const { chromium } = require('playwright');
const extensionPath = 'path/to/capsolver extension';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
],
});
const [page] = context.pages();
await page.goto('https://www.capsolver.com/blog/All');
await browser.close();
})();
Solving reCAPTCHA v2 Using the CapSolver Extension
CAPTCHA types like reCAPTCHA v2/v3, Cloudflare Turnstile, AWS WAF, are widely used across thousands of websites. Despite their popularity, these CAPTCHAs typically have consistent and detectable DOM structures. That’s where CapSolver Extension comes in — it detects and solves them automatically without the need for manual interaction.
Let’s take reCAPTCHA v2 as an example to demonstrate how to solve it using the CapSolver Extension in Playwright.
Note: Unless stated otherwise, the following examples use the click mode (/assets/config.js -> reCaptchaMode: 'click'
).
⚠️ Don’t forget to unzip the extension zip file and configure your
apiKey
in/assets/config.js
javascript
const { chromium } = require('playwright');
// Step 1: Download the extension from GitHub: https://github.com/capsolver/capsolver-browser-extension/releases
// Step 2: Unzip the extension file and set your apiKey in /assets/config.js
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
// The extension will automatically detect and solve the reCAPTCHA.
await page.waitForTimeout(15000); // Wait for solving
await page.click('button[type="submit"]');
await page.waitForTimeout(5000);
await context.close();
})();
⚠️ The CapSolver extension also supports many useful configuration options. Below are some common examples (Note: All configurations are set in
/assets/config.js
)
Configuration Option: solvedCallback
As you may have noticed, in the previous code we waited 15 seconds after loading the page before clicking the submit button. This delay was intended to give the CapSolver extension enough time to automatically solve the reCAPTCHA. However, this approach isn't ideal—sometimes the CAPTCHA is solved much faster, and in poor network conditions, it might take even longer than 15 seconds.
That's where the solvedCallback
comes in. It provides a better solution by triggering a callback once the CAPTCHA has been solved, notifying you that verification is complete. You can configure the solvedCallback
in /assets/config.js
by defining a custom function name—by default, it's captchaSolvedCallback
. Then, use page.exposeFunction
in Playwright to expose this function within the browser context.
Let’s now improve our previous code using this approach.
javascript
const { chromium } = require('playwright');
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
await page.exposeFunction('captchaSolvedCallback', async () => {
console.log('Captcha solved!');
const iframe = await page.$('iframe[src*="recaptcha"]');
if (iframe) {
const frame = await iframe.contentFrame();
const finished = await frame.evaluate(() => {
const element = document.querySelector('.recaptcha-checkbox-border');
return element && window.getComputedStyle(element).display === 'none';
});
if (finished) {
console.log('Verification completed!');
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
await context.close();
} else {
console.log('Verification not complete. Retrying...');
}
}
});
})();
For reCAPTCHA v2, sometimes multiple image challenges may appear. So after each challenge, we check if the "I'm not a robot" checkbox has been checked—if it’s gone, the verification is considered complete.
Config Option: manualSolving
In earlier examples, CAPTCHA solving began immediately upon page load. However, in some scenarios, you may need to perform other tasks first—like entering a username/password—before triggering CAPTCHA solving. Starting too early might cause the token to expire.
To handle this, set manualSolving: true
in /assets/config.js
, which allows you to manually trigger the CAPTCHA-solving process.
There are two ways to trigger solving:
- Simulate a click on the CapSolver button in the extension.
- Execute:
window.postMessage({ type: 'capsolverSolve' });
⚠️ Note: This feature is only supported in extension versions higher than v1.16.0!
Example:
javascript
const { chromium } = require('playwright');
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
// Simulate filling in credentials
await page.evaluate(() => {
const inputA = document.querySelector('input[name="ex-a"]');
inputA.value = 'username';
const inputB = document.querySelector('input[name="ex-b"]');
inputB.value = 'password';
});
// Simulate other delays or user activity
for (let i = 1; i <= 5; i++) {
await page.waitForTimeout(1000);
console.log(`Waited ${i} seconds...`);
}
console.log('Start solving CAPTCHA...');
// Method 1: Simulate clicking the CapSolver button
await page.evaluate(() => {
document.querySelector('#capsolver-solver-tip-button').click();
});
// Method 2: Trigger using postMessage
// await page.evaluate(() => {
// window.postMessage({ type: 'capsolverSolve' });
// });
await page.exposeFunction('captchaSolvedCallback', async () => {
console.log('Captcha solved!');
const iframe = await page.$('iframe[src*="recaptcha"]');
if (iframe) {
const frame = await iframe.contentFrame();
const finished = await frame.evaluate(() => {
const element = document.querySelector('.recaptcha-checkbox-border');
return element && window.getComputedStyle(element).display === 'none';
});
if (finished) {
console.log('Verification completed!');
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
await context.close();
} else {
console.log('Verification not complete. Try again.');
}
}
});
})();
Config Option: reCaptchaMode
The reCaptchaMode
setting supports two modes: click
and token
.
- click mode simulates human interaction—clicking through the image challenges.
- token mode directly uses the CapSolver API to obtain a solution token without UI interaction.
If you're experiencing multiple rounds of image selection using click
mode, it's likely due to a low browser fingerprint score. Switching to token
mode is recommended for better reliability.
Click Mode | Token Mode |
---|---|
![]() |
![]() |
Configuration Option: showSolveButton
When showSolveButton
is set to false
(default is true
), the CapSolver button will no longer be displayed on the page. However, this will not affect the normal CAPTCHA-solving functionality.

Configuration Option: useProxy
After setting useProxy: true
, you can specify the following parameters: proxyType
, hostOrIp
, port
, proxyLogin
, and proxyPassword
. With this setup, we will use your custom proxy to solve the CAPTCHA. When should you use your own proxy? Typically, in the following situations:
- Your proxy provides better quality (e.g., reCAPTCHA tokens generated using your proxy receive higher scores) or faster solving speed;
- In certain cases, the IP used to solve the CAPTCHA must be the same as the IP used to submit the token.
The above are some commonly used configuration options. You can adjust other settings according to your actual needs. If you have any questions, please contact our customer support.
Solving ImageToText CAPTCHAs Using CapSolver Extension
Unlike third-party CAPTCHAs such as reCAPTCHA, Cloudflare Turnstile, AWS WAF, or GeeTest, there’s another type of CAPTCHA that requires recognizing letters or digits from an image. We refer to these as ImageToText CAPTCHAs. They typically look like this:
ImageToText is a CAPTCHA implemented by website administrators themselves. Unlike third-party CAPTCHAs, ImageToText CAPTCHAs are custom-made by website owners. Because these CAPTCHAs vary in placement across different websites and pages, the CapSolver Extension cannot automatically detect which images are CAPTCHAs. Therefore, you must explicitly inform the CapSolver Extension in your code. Here's how to do it:
- Add a
capsolver-image-to-text-source
attribute with the value0
to the image element of the CAPTCHA; - Add a
capsolver-image-to-text-result
attribute with the value0
to the input field where the result should be filled in.
These attributes—capsolver-image-to-text-source
and capsolver-image-to-text-result
—can be configured in /assets/config.js
using the fields textCaptchaSourceAttribute
and textCaptchaResultAttribute
, respectively.
Let’s walk through an example using the site:
https://captcha.com/demos/features/captcha-demo.aspx
First, inspect the page source to locate the CAPTCHA image element and the result input field. In this case:
- CAPTCHA image element ID:
demoCaptcha_CaptchaImage
- Input field ID for the result:
captchaCode
(Screenshot below)

Now, let's use Playwright to automate solving this CAPTCHA by marking these elements accordingly:
javascript
const { chromium } = require('playwright');
// Step 1: Get the extension from GitHub (https://github.com/capsolver/capsolver-browser-extension/releases)
// Step 2: Unzip the extension zip file and configure your apiKey in /assets/config.js
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://captcha.com/demos/features/captcha-demo.aspx');
await page.waitForSelector('#demoCaptcha_CaptchaImage');
// Tell the CapSolver Extension where the CAPTCHA image is located
await page.evaluate(() => {
const imgElement = document.querySelector('#demoCaptcha_CaptchaImage');
if (imgElement) {
imgElement.setAttribute('capsolver-image-to-text-source', '0');
}
});
// Tell the CapSolver Extension where the recognition result should be input
await page.evaluate(() => {
const resultElement = document.querySelector('#captchaCode');
if (resultElement) {
resultElement.setAttribute('capsolver-image-to-text-result', '0');
}
});
// Wait for the CAPTCHA to be solved and submit the form
await page.exposeFunction('captchaSolvedCallback', async () => {
console.log('Captcha solved!');
await page.waitForTimeout(3000);
await page.click('#validateCaptchaButton');
await page.waitForTimeout(3000);
await context.close();
});
})();
Result:

How to Integrate CapSolver API with Playwright
Using the CapSolver Extension is convenient and quick, but if you're an experienced developer, we highly recommend using the API integration instead. Compared to the extension-based method, the API approach offers several key advantages:
- More customizable parameters – You can fine-tune your requests to better fit nearly all CAPTCHA scenarios.
- Greater control – You can decide exactly when and how to solve the CAPTCHA.
- More detailed error messages – These help developers perform targeted optimizations.
Before we dive into the code demo, here's a quick overview of how to use the CapSolver API:
- Step 1: https://api.capsolver.com/createTask — Create a task
- Step 2: https://api.capsolver.com/getTaskResult — Get the task result
To create a task, you'll need to send a JSON object to CapSolver. This JSON includes your clientKey
, websiteURL
, websiteKey
, and other data. These fields vary depending on the CAPTCHA type and website.
👉 For details, refer to our documentation:documentation
Solving reCAPTCHA v2 with CapSolver API
Before solving reCAPTCHA v2, please read the documentation here:
📖 ReCaptchaV2
This guide explains which JSON parameters to include when creating a task.
Additionally, you can use the CapSolver Extension to quickly generate JSON data for your API requests.
See this blog for help:
🔗 obtain the JSON data
Let's take the following example:
🔗 https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php
The JSON required to create a task for this page is:
json
{
"type": "ReCaptchaV2TaskProxyLess",
"websiteKey": "6LfW6wATAAAAAHLqO2pb8bDBahxlMxNdo9g947u9",
"websiteURL": "https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php"
}
We also provide JavaScript code samples for using the API in our documentation:

Integration in Playwright:
javascript
const { chromium } = require('playwright');
const axios = require('axios');
// Replace with your API key
const api_key = 'YOUR_API_KEY';
const captcha_type = 'ReCaptchaV2TaskProxyLess';
const site_key = '6LfW6wATAAAAAHLqO2pb8bDBahxlMxNdo9g947u9';
const site_url = 'https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php';
async function capSolver() {
const payload = {
clientKey: api_key,
task: {
type: captcha_type,
websiteKey: site_key,
websiteURL: site_url
}
};
try {
const res = await axios.post('https://api.capsolver.com/createTask', payload);
const task_id = res.data.taskId;
if (!task_id) {
console.log('Failed to create task:', res.data);
return;
}
console.log('Got taskId:', task_id);
while (true) {
await new Promise(resolve => setTimeout(resolve, 1000)); // Delay for 1 second
const getResultPayload = { clientKey: api_key, taskId: task_id };
const resp = await axios.post('https://api.capsolver.com/getTaskResult', getResultPayload);
const status = resp.data.status;
if (status === 'ready') {
return resp.data.solution.gRecaptchaResponse;
}
if (status === 'failed' || resp.data.errorId) {
console.log('Solve failed! response:', resp.data);
return;
}
}
} catch (error) {
console.error('Error:', error);
}
}
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: ['--lang=en-US'],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
const token = await capSolver();
console.log("Token:", token);
// Set the token value
await page.evaluate((token) => {
const textarea = document.getElementById('g-recaptcha-response');
if (textarea) {
textarea.value = token;
}
}, token);
await page.click('button[type="submit"]');
await page.waitForTimeout(5000);
await context.close();
})();
Solve ImageToText with CapSolver API
We still use the example of https://captcha.com/demos/features/captcha-demo.aspx, where the captcha image element has the id demoCaptcha_CaptchaImage
, and the result input element has the id captchaCode
, as shown in the following image:

For ImageToTextTask, we need to pass the base64 value of the captcha image to CapSolver. The example code is as follows:
javascript
const { chromium } = require('playwright');
const axios = require('axios');
// Replace with your API key
const api_key = 'YOUR_API_KEY';
const captcha_type = 'ImageToTextTask';
const site_url = 'https://captcha.com/demos/features/captcha-demo.aspx';
async function capSolver(base64Image) {
const payload = {
clientKey: api_key,
task: {
type: captcha_type,
websiteURL: site_url,
body: base64Image,
}
};
try {
const res = await axios.post('https://api.capsolver.com/createTask', payload);
const status = res.data.status;
if (status === 'ready') {
return res.data.solution.text;
}
if (status === 'failed' || res.data.errorId) {
console.log('Solve failed! response:', res.data);
return "";
}
} catch (error) {
console.error('Error:', error);
}
}
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: ['--lang=en-US'],
});
const [page] = context.pages();
await page.goto('https://captcha.com/demos/features/captcha-demo.aspx');
await page.waitForSelector('#demoCaptcha_CaptchaImage');
// Get the base64 value of the captcha image
const captchaImage = await page.evaluate(() => {
const img = document.querySelector('img[id="demoCaptcha_CaptchaImage"]');
return img ? img.getAttribute('src') : null;
});
const base64Image = captchaImage.split(',')[1];
const text = await capSolver(base64Image);
console.log("Text:", text);
// Set the solved captcha text
await page.evaluate((text) => {
document.getElementById('captchaCode').value = text;
}, text);
await page.click('#validateCaptchaButton');
await page.waitForTimeout(5000);
await context.close();
})();
Additionally, for some special ImageToText types, you can specify different models to improve accuracy. For details, please refer to our documentation:
https://docs.capsolver.com/en/guide/recognition/ImageToTextTask/

Useful References
- CapSolver Documentation
- CapSolver Extension GitHub Releases
- CapSolver Extension on Chrome Web Store
- CapSolver Extension on Firefox Add-ons
- Human-like Score Solver for reCAPTCHA v3
Demo Videos Featuring the CapSolver Extension:
- Solve reCAPTCHA v3 with CapSolver Chrome Extension
- Solve reCAPTCHA v2 with CapSolver Chrome Extension
- Solve reCAPTCHA with Puppeteer & CapSolver Extension
- Solve ImageToText with Puppeteer & CapSolver Extension
Additionally, CapSolver offers a Developer Revenue Sharing Program, allowing developers and partners to earn commissions by integrating or promoting CapSolver solutions. It’s a great way to monetize your work while helping others solve captchas efficiently. For full details, check out:
CapSolver Developer Plan
Conclusion
Playwright's robust features, combined with CapSolver's ability to handle CAPTCHAs, offer a comprehensive solution for web automation. Whether using the CapSolver extension for convenience or the API for greater control, this integration streamlines complex tasks and enhances automation workflows. Beyond just solving CAPTCHAs, remember that CapSolver also offers a Developer Revenue Sharing Program, providing an excellent opportunity to earn commissions by integrating or promoting their solutions
Compliance Disclaimer: The information provided on this blog is for informational purposes only. CapSolver is committed to compliance with all applicable laws and regulations. The use of the CapSolver network for illegal, fraudulent, or abusive activities is strictly prohibited and will be investigated. Our captcha-solving solutions enhance user experience while ensuring 100% compliance in helping solve captcha difficulties during public data crawling. We encourage responsible use of our services. For more information, please visit our Terms of Service and Privacy Policy.
More

How to Integrate CapSolver — Seamless Captcha Solutions for Automation
Easily integrate CapSolver into your automation or scraping workflows. Fast setup, high accuracy, and developer-friendly tools included.

Ethan Collins
12-Jun-2025

How to Integrate CapSolver with Selenium | Complete Guide 2025
Selenium & CapSolver integration for seamless CAPTCHA solution. Learn extension, API, and SDK methods for robust web automation.

Lucas Mitchell
09-Jun-2025

How to Integrate CapSolver with Playwright | Complete Guide 2025
This article covers the integration of Playwright with CapSolver, introducing the Playwright framework, its features, and use cases. It focuses on how to integrate CapSolver Extension and API in Playwright to solve various types of CAPTCHA challenges.

Ethan Collins
04-Jun-2025

How to Integrate CapSolver with Puppeteer | Complete Guide 2025
Easily integrate CapSolver extension with Puppeteer to automate CAPTCHA solving and boost your web scraping success.

Lucas Mitchell
29-May-2025

AI-powered Image Recognition: The Basics and How to Solve it
Say goodbye to image CAPTCHA struggles – CapSolver Vision Engine solves them fast, smart, and hassle-free!

Lucas Mitchell
24-Apr-2025

Best User Agents for Web Scraping & How to Use Them
A guide to the best user agents for web scraping and their effective use to avoid detection. Explore the importance of user agents, types, and how to implement them for seamless and undetectable web scraping.

Ethan Collins
07-Mar-2025