How to bypass captcha in Burp Suite with solver
Burp Suite is widely used for web application security testing, request inspection, and API analysis.
Captchas can interrupt this workflow. A protected login, registration form, or API request may require a valid captcha token before the server processes the request.
With the SolveCaptcha API, you can submit the captcha parameters, retrieve a solution token, and insert it into a request sent through Burp Repeater.
The basic workflow is:
Intercept the protected page
→ identify the captcha type
→ extract the required parameters
→ create a SolveCaptcha task
→ wait for the solution
→ retrieve the token
→ insert it into the Burp request
→ send the request
This guide focuses on reCAPTCHA v2. It also explains the changes required for Invisible reCAPTCHA v2, reCAPTCHA v3, and reCAPTCHA Enterprise.
Use this workflow only on systems you own or are explicitly authorized to test.
What Burp Suite does in this workflow
Burp Suite does not solve the captcha itself.
Burp is used to:
- inspect the protected page;
- identify the captcha parameters;
- capture the final HTTP request;
- locate the expected captcha field;
- modify the request;
- preserve cookies and headers;
- send the completed request to the server.
SolveCaptcha performs the captcha-solving step and returns the token.
The final request is still sent through Burp Suite.
Recommended integration options
There are two practical ways to connect Burp Suite with SolveCaptcha.
External Python helper
A standalone Python script creates the task and prints the completed token.
You then paste the token into Burp Repeater.
This is the simplest option and is usually easier to debug.
Burp extension
A Burp extension can detect a placeholder in a Repeater request, request a new token, and replace the placeholder before the request is sent.
This reduces manual work but requires additional configuration.
Start with the external helper. Add the extension only after the basic workflow works correctly.
Requirements
You need:
- Burp Suite Community or Professional;
- Python 3 for the external helper;
- Jython when using the optional legacy Burp extension;
- a SolveCaptcha account;
- a SolveCaptcha API key;
- permission to test the target application.
Install Requests for Python:
python -m pip install requests
Store the API key in an environment variable.
Linux or macOS:
export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"
Windows PowerShell:
$env:SOLVECAPTCHA_API_KEY="YOUR_API_KEY"
Do not place the API key in browser JavaScript, public repositories, screenshots, or shared Burp project files.
Step 1: Capture the protected page
Configure your browser to use Burp Proxy.
Open the page containing the captcha and capture its HTML response.
You can inspect the response in:
- Proxy HTTP history;
- Repeater;
- Logger;
- the browser DevTools.
For reCAPTCHA v2, search the response for:
data-sitekey
Example:
<div
class="g-recaptcha"
data-sitekey="6Lc_aXkUAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u">
</div>
The site key is:
6Lc_aXkUAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u
The site key is public. It is not the private reCAPTCHA secret used by the website backend.
Alternative site key locations
The site key may also appear in a reCAPTCHA iframe URL.
Look for:
www.google.com/recaptcha/api2/anchor
Example:
https://www.google.com/recaptcha/api2/anchor?k=SITE_KEY
The site key is the value of:
k
For reCAPTCHA v3, it may appear in:
<script
src="https://www.google.com/recaptcha/api.js?render=SITE_KEY">
</script>
It may also appear in:
grecaptcha.execute(
"SITE_KEY",
{
action: "login"
}
);
Step 2: Record the correct page URL
The SolveCaptcha pageurl parameter must contain the full URL where the captcha is loaded.
Example:
https://example.com/account/login
Do not automatically use only the website origin:
https://example.com
The correct path may matter.
Preserve important query parameters when they are part of the page:
https://example.com/account/login?return=/checkout
The page URL should describe the captcha page, not necessarily the API endpoint that receives the completed form.
Step 3: Find where the token is submitted
Complete the captcha manually once and inspect the resulting request in Burp.
Search the request body for:
g-recaptcha-response
A URL-encoded form may contain:
[email protected]&password=test&g-recaptcha-response=TOKEN
A JSON request may contain:
{
"username": "[email protected]",
"password": "test",
"g-recaptcha-response": "TOKEN"
}
Some applications use a custom field:
captchaToken
recaptchaToken
verificationToken
captcha_response
Do not assume that every application sends the token under the standard field name.
Compare the request before and after a successful manual captcha completion.
SolveCaptcha API endpoints
Create a task through:
POST https://api.solvecaptcha.com/in.php
Retrieve the result through:
GET https://api.solvecaptcha.com/res.php
For standard reCAPTCHA v2, use:
method=userrecaptcha
googlekey=SITE_KEY
pageurl=PAGE_URL
Do not use unsupported request structures such as:
createTask
getTaskResult
clientKey
websiteKey
websiteURL
NoCaptchaTaskProxyless
RecaptchaV2TaskProxyless
Step 4: Create a reCAPTCHA v2 task
Example cURL request:
curl --request POST \
--url https://api.solvecaptcha.com/in.php \
--data-urlencode "key=YOUR_API_KEY" \
--data-urlencode "method=userrecaptcha" \
--data-urlencode "googlekey=6Lc_aXkUAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u" \
--data-urlencode "pageurl=https://example.com/account/login" \
--data-urlencode "json=1"
A successful response contains the task ID:
{
"status": 1,
"request": "2122988149"
}
Save the value returned in:
request
If task creation fails, the API returns an error code:
{
"status": 0,
"request": "ERROR_CODE"
}
Do not start polling unless a valid task ID was returned.
Step 5: Wait for processing
Wait approximately 15–20 seconds before requesting the first result.
Do not create another task while the first task is still being processed.
Duplicate tasks increase costs and make it harder to determine which token belongs to the current request.
Step 6: Retrieve the token
Request the result from:
https://api.solvecaptcha.com/res.php
Example:
curl "https://api.solvecaptcha.com/res.php?key=YOUR_API_KEY&action=get&id=2122988149&json=1"
If the task is still processing:
{
"status": 0,
"request": "CAPCHA_NOT_READY"
}
Wait five seconds and repeat the request with the same task ID.
When the task is complete:
{
"status": 1,
"request": "03AFcWeA5dCJ..."
}
The value in request is the reCAPTCHA token.
Complete Python helper
The following script creates a reCAPTCHA v2 task, waits for the result, and prints the completed token.
Create solve_recaptcha.py:
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import os
import sys
import time
from dataclasses import dataclass
from typing import Any
import requests
CREATE_TASK_URL = (
"https://api.solvecaptcha.com/in.php"
)
GET_RESULT_URL = (
"https://api.solvecaptcha.com/res.php"
)
INITIAL_WAIT_SECONDS = 20
POLL_INTERVAL_SECONDS = 5
MAX_WAIT_SECONDS = 180
class SolveCaptchaError(RuntimeError):
"""Raised when SolveCaptcha returns an error."""
@dataclass(frozen=True)
class CaptchaSolution:
task_id: str
token: str
def parse_response(
response: requests.Response,
) -> dict[str, Any]:
response.raise_for_status()
try:
data = response.json()
except ValueError as exc:
raise SolveCaptchaError(
"SolveCaptcha returned invalid JSON: "
f"{response.text[:500]}"
) from exc
if not isinstance(data, dict):
raise SolveCaptchaError(
f"Unexpected API response: {data!r}"
)
return data
def create_task(
*,
api_key: str,
site_key: str,
page_url: str,
invisible: bool = False,
version: str | None = None,
action: str | None = None,
min_score: float | None = None,
enterprise: bool = False,
) -> str:
payload: dict[str, Any] = {
"key": api_key,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1,
}
if invisible:
payload["invisible"] = 1
if version:
payload["version"] = version
if action:
payload["action"] = action
if min_score is not None:
payload["min_score"] = min_score
if enterprise:
payload["enterprise"] = 1
response = requests.post(
CREATE_TASK_URL,
data=payload,
timeout=30,
)
data = parse_response(
response
)
if data.get("status") != 1:
raise SolveCaptchaError(
"Task creation failed: "
f"{data.get('request')}"
)
task_id = str(
data.get("request", "")
).strip()
if not task_id:
raise SolveCaptchaError(
"SolveCaptcha did not return "
"a task ID"
)
return task_id
def get_result(
*,
api_key: str,
task_id: str,
) -> str | None:
response = requests.get(
GET_RESULT_URL,
params={
"key": api_key,
"action": "get",
"id": task_id,
"json": 1,
},
timeout=30,
)
data = parse_response(
response
)
if data.get("status") == 1:
token = str(
data.get("request", "")
).strip()
if not token:
raise SolveCaptchaError(
"SolveCaptcha returned "
"an empty token"
)
return token
error_code = str(
data.get(
"request",
"UNKNOWN_ERROR",
)
)
if error_code == "CAPCHA_NOT_READY":
return None
raise SolveCaptchaError(
f"Task failed: {error_code}"
)
def solve(
*,
api_key: str,
site_key: str,
page_url: str,
invisible: bool = False,
version: str | None = None,
action: str | None = None,
min_score: float | None = None,
enterprise: bool = False,
) -> CaptchaSolution:
task_id = create_task(
api_key=api_key,
site_key=site_key,
page_url=page_url,
invisible=invisible,
version=version,
action=action,
min_score=min_score,
enterprise=enterprise,
)
time.sleep(
INITIAL_WAIT_SECONDS
)
deadline = (
time.monotonic()
+ MAX_WAIT_SECONDS
)
while time.monotonic() < deadline:
token = get_result(
api_key=api_key,
task_id=task_id,
)
if token is not None:
return CaptchaSolution(
task_id=task_id,
token=token,
)
time.sleep(
POLL_INTERVAL_SECONDS
)
raise TimeoutError(
f"Task {task_id} was not completed "
f"within {MAX_WAIT_SECONDS} seconds"
)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description=(
"Request a reCAPTCHA token "
"from SolveCaptcha."
)
)
parser.add_argument(
"--site-key",
required=True,
)
parser.add_argument(
"--page-url",
required=True,
)
parser.add_argument(
"--invisible",
action="store_true",
)
parser.add_argument(
"--version",
choices=["v3"],
)
parser.add_argument(
"--action",
)
parser.add_argument(
"--min-score",
type=float,
)
parser.add_argument(
"--enterprise",
action="store_true",
)
return parser
def main() -> None:
api_key = os.environ.get(
"SOLVECAPTCHA_API_KEY",
"",
).strip()
if not api_key:
raise SystemExit(
"Set SOLVECAPTCHA_API_KEY"
)
parser = build_parser()
arguments = parser.parse_args()
try:
solution = solve(
api_key=api_key,
site_key=arguments.site_key,
page_url=arguments.page_url,
invisible=arguments.invisible,
version=arguments.version,
action=arguments.action,
min_score=arguments.min_score,
enterprise=arguments.enterprise,
)
except (
requests.RequestException,
SolveCaptchaError,
TimeoutError,
) as error:
print(
f"Error: {error}",
file=sys.stderr,
)
raise SystemExit(1) from error
print(solution.token)
if __name__ == "__main__":
main()
Run it for standard reCAPTCHA v2:
python solve_recaptcha.py \
--site-key "6Lc_aXkUAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u" \
--page-url "https://example.com/account/login"
The script prints only the token:
03AFcWeA5dCJ...
This makes it easy to copy the value into Burp Repeater.
Step 7: Insert the token in Burp Repeater
Send the protected request to Repeater.
Locate the captcha field and replace its current value with the SolveCaptcha token.
URL-encoded form
Before:
POST /account/login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=test%40example.com&password=test&g-recaptcha-response=
After:
POST /account/login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=test%40example.com&password=test&g-recaptcha-response=03AFcWeA5dCJ...
Burp recalculates Content-Length when the request is sent.
JSON body
Before:
{
"username": "[email protected]",
"password": "test",
"captchaToken": ""
}
After:
{
"username": "[email protected]",
"password": "test",
"captchaToken": "03AFcWeA5dCJ..."
}
Multipart form
A multipart request may contain:
Content-Disposition: form-data; name="g-recaptcha-response"
03AFcWeA5dCJ...
Preserve the existing multipart boundary and field formatting.
Do not inject the token into HTML in Repeater
When using Burp Repeater, you normally do not need to modify the HTML response or execute the page callback.
Burp sends the final HTTP request directly to the server.
The important step is to place the token where the backend expects it:
- form field;
- JSON property;
- multipart field;
- custom header;
- another application-specific parameter.
Browser-side callbacks matter when automating the actual page. They are usually unnecessary when reproducing the final request directly in Repeater.
Preserve the original session
A captcha token may depend on the session that generated the challenge.
Keep the relevant request context unchanged:
- cookies;
- CSRF token;
- User-Agent;
- page URL;
- account state;
- proxy or source IP;
- request order.
Do not generate the token for one session and submit it from an unrelated Burp project or browser profile.
If the application issues a new CSRF token or captcha challenge, capture fresh parameters and request a new solution.
Invisible reCAPTCHA v2
Invisible reCAPTCHA v2 uses the same base method.
Add:
invisible=1
Run the helper with:
python solve_recaptcha.py \
--site-key "SITE_KEY" \
--page-url "https://example.com/account/login" \
--invisible
The returned token is still commonly submitted through:
g-recaptcha-response
When editing the final request in Burp, the browser callback normally does not need to be executed.
reCAPTCHA v3
For reCAPTCHA v3, add:
version=v3
action=ACTION
min_score=SCORE
Example:
python solve_recaptcha.py \
--site-key "SITE_KEY" \
--page-url "https://example.com/account/login" \
--version v3 \
--action login \
--min-score 0.3
The action must match the value used by the website.
Look for:
grecaptcha.execute(
"SITE_KEY",
{
action: "login"
}
);
Do not guess between similar values such as:
login
signin
authenticate
verify
The server may reject a valid token when its action does not match.
reCAPTCHA Enterprise
For reCAPTCHA Enterprise, add:
enterprise=1
Example:
python solve_recaptcha.py \
--site-key "SITE_KEY" \
--page-url "https://example.com/account/login" \
--enterprise
For Enterprise v3:
python solve_recaptcha.py \
--site-key "SITE_KEY" \
--page-url "https://example.com/account/login" \
--version v3 \
--action login \
--min-score 0.3 \
--enterprise
Enterprise integrations can require additional values. Inspect the page and the successful browser request before reproducing the workflow in Burp.
Optional Burp Repeater extension
The following Jython extension watches requests sent from Repeater.
When the request body contains:
__SOLVECAPTCHA_TOKEN__
the extension:
- creates a reCAPTCHA v2 task;
- waits for the token;
- replaces the placeholder;
- sends the modified request.
The extension processes only Repeater requests and only the configured hostname.
This example is intended for low-volume authorized testing. It blocks the Repeater request while the captcha is being solved.
# -*- coding: utf-8 -*-
from burp import IBurpExtender
from burp import IHttpListener
import json
import os
import threading
import time
import urllib
import urllib2
API_KEY = os.environ.get(
"SOLVECAPTCHA_API_KEY",
"",
).strip()
ALLOWED_HOST = "example.com"
SITE_KEY = (
"6Lc_aXkUAAAAAJs_"
"eEHvoOl75_83eXSqpPSRFJ_u"
)
PAGE_URL = (
"https://example.com/account/login"
)
PLACEHOLDER = (
"__SOLVECAPTCHA_TOKEN__"
)
CREATE_TASK_URL = (
"https://api.solvecaptcha.com/in.php"
)
GET_RESULT_URL = (
"https://api.solvecaptcha.com/res.php"
)
class BurpExtender(
IBurpExtender,
IHttpListener,
):
def registerExtenderCallbacks(
self,
callbacks,
):
self.callbacks = callbacks
self.helpers = (
callbacks.getHelpers()
)
self.lock = threading.Lock()
callbacks.setExtensionName(
"SolveCaptcha Repeater Injector"
)
callbacks.registerHttpListener(
self
)
callbacks.printOutput(
"SolveCaptcha Repeater Injector loaded"
)
def processHttpMessage(
self,
toolFlag,
messageIsRequest,
messageInfo,
):
if not messageIsRequest:
return
if (
toolFlag
!= self.callbacks.TOOL_REPEATER
):
return
request = messageInfo.getRequest()
request_info = (
self.helpers.analyzeRequest(
messageInfo
)
)
url = request_info.getUrl()
if url.getHost() != ALLOWED_HOST:
return
body_offset = (
request_info.getBodyOffset()
)
request_string = (
self.helpers.bytesToString(
request
)
)
body = request_string[
body_offset:
]
if PLACEHOLDER not in body:
return
if not API_KEY:
self.callbacks.printError(
"SOLVECAPTCHA_API_KEY is not set"
)
return
with self.lock:
try:
token = (
self.solve_recaptcha()
)
headers = list(
request_info.getHeaders()
)
content_type = (
self.find_header(
headers,
"Content-Type",
)
or ""
).lower()
if (
"application/"
"x-www-form-urlencoded"
in content_type
):
replacement = (
urllib.quote_plus(
token
)
)
else:
replacement = token
new_body = body.replace(
PLACEHOLDER,
replacement,
)
new_request = (
self.helpers.buildHttpMessage(
headers,
self.helpers.stringToBytes(
new_body
),
)
)
messageInfo.setRequest(
new_request
)
self.callbacks.printOutput(
"Captcha token inserted "
"into Repeater request"
)
except Exception as error:
self.callbacks.printError(
"SolveCaptcha error: "
+ str(error)
)
def find_header(
self,
headers,
name,
):
prefix = name.lower() + ":"
for header in headers:
if (
header.lower()
.startswith(prefix)
):
return header.split(
":",
1,
)[1].strip()
return None
def post_form(
self,
url,
parameters,
):
encoded = urllib.urlencode(
parameters
)
request = urllib2.Request(
url,
encoded,
)
response = urllib2.urlopen(
request,
timeout=30,
)
return json.loads(
response.read()
)
def get_json(
self,
url,
parameters,
):
request_url = (
url
+ "?"
+ urllib.urlencode(
parameters
)
)
response = urllib2.urlopen(
request_url,
timeout=30,
)
return json.loads(
response.read()
)
def solve_recaptcha(self):
create_result = self.post_form(
CREATE_TASK_URL,
{
"key": API_KEY,
"method": (
"userrecaptcha"
),
"googlekey": SITE_KEY,
"pageurl": PAGE_URL,
"json": 1,
},
)
if (
create_result.get("status")
!= 1
):
raise RuntimeError(
"Task creation failed: "
+ str(
create_result.get(
"request"
)
)
)
task_id = str(
create_result.get(
"request"
)
)
time.sleep(20)
deadline = (
time.time() + 180
)
while time.time() < deadline:
result = self.get_json(
GET_RESULT_URL,
{
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
},
)
if result.get("status") == 1:
token = str(
result.get(
"request",
"",
)
).strip()
if not token:
raise RuntimeError(
"Empty token returned"
)
return token
error_code = str(
result.get(
"request",
"UNKNOWN_ERROR",
)
)
if (
error_code
!= "CAPCHA_NOT_READY"
):
raise RuntimeError(
"Task failed: "
+ error_code
)
time.sleep(5)
raise RuntimeError(
"Captcha solving timed out"
)
Configure the extension
Set these constants before loading the extension:
ALLOWED_HOST = "example.com"
SITE_KEY = "SITE_KEY"
PAGE_URL = "https://example.com/account/login"
Set the SolveCaptcha API key before starting Burp:
export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"
Load the Jython file through Burp Extender.
Then place the placeholder in the Repeater request:
g-recaptcha-response=__SOLVECAPTCHA_TOKEN__
When you click Send, the extension requests a fresh token and replaces the placeholder.
Extension limitations
The example extension is intentionally narrow.
It:
- works only in Repeater;
- processes one configured hostname;
- solves standard reCAPTCHA v2;
- replaces placeholders only in the request body;
- waits synchronously for the solution;
- does not detect the site key automatically;
- does not process Intruder requests;
- does not support high-volume traffic.
For Invisible v2, v3, or Enterprise, update the parameters inside solve_recaptcha().
Do not remove the hostname and Repeater restrictions unless you have a clear authorized testing requirement.
Common errors
ERROR_WRONG_USER_KEY
The API key is invalid.
Copy the key again from the SolveCaptcha account settings.
Check for spaces, missing characters, or an unset environment variable.
ERROR_ZERO_BALANCE
The account balance is insufficient.
Add funds before creating another task.
ERROR_CAPTCHA_UNSOLVABLE
The task could not be completed.
Check:
- the site key;
- the page URL;
- the captcha version;
- Invisible or Enterprise parameters;
- the v3 action;
- the requested v3 score.
Capture fresh parameters before retrying.
CAPCHA_NOT_READY
The task is still processing.
Wait five seconds and request the result again with the same task ID.
Do not create another task.
Server rejects the token
Possible causes include:
- incorrect site key;
- incorrect page URL;
- expired token;
- token generated for another session;
- missing CSRF token;
- incorrect reCAPTCHA action;
- wrong request field;
- changed cookies;
- changed source IP;
- another server-side validation error.
Compare the modified request with a successful request generated through the browser.
Repeater returns HTTP 403
A valid captcha token does not bypass every security control.
The request may still fail because of:
- missing cookies;
- invalid CSRF state;
- expired session;
- blocked IP address;
- incorrect headers;
- account restrictions;
- WAF rules;
- rate limits.
Inspect the response instead of assuming the captcha token was incorrect.
Token works in the browser but not in Repeater
The token may be tied to the browser session.
Copy the complete browser request to Repeater and preserve:
- cookies;
- User-Agent;
- page URL;
- CSRF value;
- request body;
- proxy path.
Request a fresh token immediately before sending the Repeater request.
No site key is visible in the HTML
The captcha may be rendered dynamically.
Search:
- loaded JavaScript;
- iframe URLs;
grecaptcha.render;grecaptcha.execute;- the Network history;
- the browser DOM after JavaScript executes.
Common implementation mistakes
Using createTask and getTaskResult
Incorrect:
createTask
getTaskResult
clientKey
taskId
Correct:
in.php
res.php
key
request
Using websiteKey instead of googlekey
Incorrect:
websiteKey=SITE_KEY
Correct:
googlekey=SITE_KEY
Using websiteURL instead of pageurl
Incorrect:
websiteURL=PAGE_URL
Correct:
pageurl=PAGE_URL
Injecting the token into the HTML response
When using Repeater, modify the final outgoing request.
There is usually no reason to edit the page HTML.
Reusing a token
Treat each token as short-lived and single-use.
Sending the token to the wrong endpoint
Generate the token for the page where the captcha appears, then submit it through the request expected by the application.
Ignoring URL encoding
URL-encode the token when inserting it into an application/x-www-form-urlencoded body.
Do not URL-encode it inside a normal JSON string.
Losing the original cookies
Repeater does not automatically reproduce every browser state change.
Confirm that the request contains the active session and CSRF cookies.
Automating unlimited retries
Set a fixed polling timeout and stop when it is reached.
Do not create tasks indefinitely.
Recommended Burp workflow
A reliable manual workflow is:
- Open the target page through Burp Proxy.
- Record the request and response sequence.
- Find the captcha site key.
- Record the exact page URL.
- Complete the captcha manually once.
- Identify the token field in the final request.
- Send that request to Repeater.
- Replace the old token with an empty value or placeholder.
- Request a fresh token through SolveCaptcha.
- Insert the token into the correct request field.
- Preserve cookies, CSRF values, and headers.
- Send the request before the token expires.
- Review the complete server response.
This approach is easier to debug than attempting full automation immediately.
Pre-launch checklist
Before using the workflow, confirm:
- [ ] The target application is within the authorized test scope.
- [ ] The captcha type has been identified correctly.
- [ ] The current site key was extracted.
- [ ] The full captcha page URL is correct.
- [ ] The final token field was identified.
- [ ] Active cookies are present in Repeater.
- [ ] The CSRF token is still valid.
- [ ]
method=userrecaptchais used. - [ ] The site key is sent as
googlekey. - [ ] The page URL is sent as
pageurl. - [ ] Invisible, v3, or Enterprise parameters are included when required.
- [ ] The first result request waits approximately 15–20 seconds.
- [ ] Later result requests use five-second intervals.
- [ ] The completed token is read from
request. - [ ] URL encoding matches the request content type.
- [ ] A fresh token is used for each test attempt.
Frequently asked questions
Can Burp Suite solve captchas by itself?
No. Burp captures and modifies HTTP traffic. SolveCaptcha performs the solving step.
Which SolveCaptcha method is used for reCAPTCHA v2?
Use:
method=userrecaptcha
Where do I send the site key?
Use:
googlekey=SITE_KEY
Which page URL should I send?
Use the complete URL where the captcha is loaded.
Where is the token returned?
With json=1, the completed token is returned in:
request
Where should I insert the token?
Insert it into the same request field used by the browser after a successful manual solve.
The standard field is often:
g-recaptcha-response
Do I need to invoke the JavaScript callback?
Not when you are reproducing the final HTTP request directly in Repeater.
The callback is part of the browser workflow. The server normally receives only the resulting token.
Can I use this with Invisible reCAPTCHA?
Yes.
Add:
invisible=1
Can I use this with reCAPTCHA v3?
Yes.
Add:
version=v3
action=ACTION
min_score=SCORE
Can I use it with reCAPTCHA Enterprise?
Yes.
Add:
enterprise=1
Can I reuse a token?
No. Request a fresh token for each new challenge or test attempt.
Should I use this with Intruder?
The example is designed for controlled Repeater testing.
High-volume automated credential attacks or requests outside the authorized scope are not appropriate uses of this workflow.
Conclusion
Bypassing captcha in Burp Suite requires coordination between Burp, the active application session, and the SolveCaptcha API.
The correct workflow is:
- Capture the protected page through Burp Proxy.
- Identify the captcha type.
- Extract the public site key.
- Record the complete page URL.
- Inspect a successful browser request.
- Find the field containing the captcha token.
- Submit the captcha parameters to
in.php. - Save the task ID returned in
request. - Wait approximately 15–20 seconds.
- Poll
res.phpevery five seconds. - Read the completed token from
request. - Insert the token into the Repeater request.
- Preserve cookies, CSRF values, headers, and session state.
- Send the request before the token expires.
- Review the complete response for other validation failures.
Use the SolveCaptcha API documentation to verify the current parameters for each supported captcha type.