Was this helpful?
How to bypass Cloudflare Challenge on VFS Global
Technical engineer
Introduction
VFS Global is the world's largest visa center operator, using Cloudflare Turnstile to protect login and registration forms from automation. Unlike standard implementations, VFS Global uses dynamic parameters (data, pagedata, action) that are generated with each interaction with the form.
In this guide, we will break down how to intercept these dynamic parameters using a special script, solve the captcha via the 2Captcha API, and correctly inject the token into the page using a callback function.
Task parameters
To bypass Cloudflare Turnstile, the TurnstileTask task type is used. For VFS Global, it is critical to pass not only the sitekey but also the dynamic parameters, as well as the exact User-Agent.
json
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "TurnstileTaskProxyless",
"websiteURL": "https://visa.vfsglobal.com/tur/en/fra/login",
"websiteKey": "0x4AAAAAAAAjq6WYeRDKmebM",
"data": "dynamic_data_string_here",
"pagedata": "dynamic_pagedata_string_here",
"action": "login",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
}
How to find parameters
websiteURL
The full address of the page with the captcha. For example: https://visa.vfsglobal.com/tur/en/fra/login
websiteKey (sitekey)
The public Cloudflare Turnstile key. For the specified VFS Global site, it is: 0x4AAAAAAAAjq6WYeRDKmebM
Dynamic parameters (data, pagedata, action, userAgent)
These parameters change with each page load. To get them, you need to inject a special interception script into the browser console (DevTools) BEFORE the captcha loads.
Instructions:
- Open the login page in incognito mode and press F12 (Developer Tools).
- Go to the Console tab.
- Paste the following script and press Enter. Do not refresh the page after this!
javascript
const i = setInterval(()=>{
if (window.turnstile) {
clearInterval(i)
window.turnstile.render = (a,b) => {
let p = {
type: "TurnstileTaskProxyless",
websiteKey: b.sitekey,
websiteURL: window.location.href,
data: b.cData,
pagedata: b.chlPageData,
action: b.action,
userAgent: navigator.userAgent
}
console.log(JSON.stringify(p))
window.tsCallback = b.callback
return 'foo'
}
}
}, 10)
- Perform the action that triggers the captcha (for example, enter email and password and click the login button).
- A JSON object with the current parameters will instantly appear in the console. Copy them.
- Immediately send these parameters in the solving request via the API. Do not refresh the page, otherwise the parameters will become invalid.
Code examples
Python + requests (Getting the token)
Used to send a task to the API after you have extracted the dynamic parameters via the console.
python
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
from twocaptcha import TwoCaptcha
api_key = os.getenv('APIKEY_2CAPTCHA', 'YOUR_API_KEY')
solver = TwoCaptcha(api_key)
try:
result = solver.turnstile(
sitekey='0x4AAAAAAAAjq6WYeRDKmebM',
url='https://visa.vfsglobal.com/tur/en/fra/login',
action='login',
data='extracted_data_value',
pagedata='extracted_pagedata_value',
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'
)
print(f"Token successfully received: {result['code']}")
except Exception as e:
print(f"An error occurred: {e}")
Python + Selenium (Automation with injection)
An adapted script based on the provided file. Uses seleniumbase Driver (undetected-chromedriver) to bypass basic detection, intercepts parameters, and injects the token via a callback function.
python
import time
import chromedriver_autoinstaller_fix
import requests
from seleniumbase import Driver
from selenium.webdriver.common.by import By
chromedriver_autoinstaller_fix.install()
agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
# Pass your own userAgent for the headless version
driver = Driver(uc=True, headless=False, proxy=False, agent=agent)
url = 'https://visa.vfsglobal.com/tur/en/fra/login'
driver.delete_all_cookies()
# Start the driver with a delay, which helps to fool the turnstile
driver.uc_open_with_reconnect(url, reconnect_time=20)
time.sleep(5)
# Close the cookies banner if it exists
try:
driver.find_element(By.CLASS_NAME, "onetrust-close-btn-handler.onetrust-close-btn-ui.banner-close-button.ot-close-icon").click()
time.sleep(2)
except:
pass
# Enter data to trigger the captcha
driver.find_element(By.ID, "mat-input-0").send_keys("alter_shmalter@gmail.com")
time.sleep(1)
driver.find_element(By.ID, "mat-input-1").send_keys("numbers12345")
time.sleep(3)
# Inject the interception script BEFORE the captcha loads
intercept_script = """
const i = setInterval(()=>{
if (window.turnstile) {
clearInterval(i)
window.turnstile.render = (a,b) => {
let p = {
type: "TurnstileTaskProxyless",
websiteKey: b.sitekey,
websiteURL: window.location.href,
data: b.cData,
pagedata: b.chlPageData,
action: b.action,
userAgent: navigator.userAgent
}
console.log("CAPTCHA_PARAMS:", JSON.stringify(p))
window.tsCallback = b.callback
return 'foo'
}
}
}, 10)
"""
driver.execute_script(intercept_script)
# Click the button that triggers the captcha (adapt the selector to the current version of the site)
driver.find_element(By.XPATH, "//button[@type='submit']").click()
time.sleep(5)
# Extract parameters from the console (in a real script, it is better to intercept them via performance logs)
# For example, let's assume we already know them or have extracted them
sitekey = "0x4AAAAAAAAjq6WYeRDKmebM"
user_agent = driver.get_user_agent()
my_key = "YOUR_2CAPTCHA_KEY"
# Send the task for solving
data = {
"key": my_key,
"method": "turnstile",
"sitekey": sitekey,
"json": 1,
"pageurl": url,
"useragent": user_agent,
# Add data, pagedata, action here if they are required for your version of the site
}
response = requests.post("https://api.2captcha.com/in.php", data=data)
print("Sent to the service:", response.text)
s = response.json()["request"]
# Wait for the result
time.sleep(15)
while True:
solu = requests.get(f"https://api.2captcha.com/res.php?key={my_key}&action=get&json=1&id={s}").json()
if solu["request"] == "CAPCHA_NOT_READY":
print(solu["request"])
time.sleep(10)
elif "ERROR" in solu["request"]:
print(solu["request"])
driver.quit()
exit(0)
else:
break
token = solu["request"]
print("Token received:", token)
# Inject the token using the callback function that we saved in window.tsCallback
driver.execute_script(f"window.tsCallback('{token}');")
# Additionally, remove the disabled attribute from the button if it is still locked
try:
el = driver.find_element(By.XPATH, "//button[@type='submit']")
driver.execute_script("arguments[0].removeAttribute('disabled')", el)
except:
pass
time.sleep(2)
# Check the injection
resp = driver.execute_script("return turnstile.getResponse();")
print("turnstile.getResponse() response:", resp)
print("Response injected")
time.sleep(10)
driver.quit()
Solution accuracy reports
If the site rejected the received token, be sure to report it via the reportIncorrect method. This helps the service improve its algorithms and refunds your funds for the failed attempt. If the token successfully passed the verification, send reportCorrect.
You can submit a report via the API:
python
import requests
API_KEY = "YOUR_API_KEY"
TASK_ID = "123456789"
# Report for an incorrect solution
requests.post(
"https://api.2captcha.com/reportIncorrect",
json={"clientKey": API_KEY, "taskId": TASK_ID}
)
# Report for a correct solution
requests.post(
"https://api.2captcha.com/reportCorrect",
json={"clientKey": API_KEY, "taskId": TASK_ID}
)
Detailed guide on submitting reports with examples for different languages: https://2captcha.com/h/how-to-submit-reports
Common errors and solutions
| Error / Problem | Cause | Solution |
|---|---|---|
| ERROR_CAPTCHA_UNSOLVABLE | Dynamic parameters (data, pagedata, action) or User-Agent are missing or incorrect. | Use the interception script to get the current parameters. Make sure that the userAgent in the task exactly matches the browser's userAgent. |
| Token received, but the site does not let you in | Incorrect token injection or expired parameter lifetime. | Use the window.tsCallback('token') call immediately after receiving the solution. Do not refresh the page between intercepting parameters and sending the request. |
| Error finding elements | The site has updated the layout or protection mechanisms. | Check the current XPath or CSS selectors via DevTools. Increase the wait time or use explicit waits (WebDriverWait). |
| ERROR_WRONG_USER_KEY | Invalid API key. | Check that you are using the correct key from your 2Captcha dashboard. |
Useful links
- Sandbox for API testing: https://2captcha.com/setting#sandbox
- Cloudflare Turnstile documentation: https://2captcha.com/api-docs/turnstile
- Detailed guide on submitting reports: https://2captcha.com/h/how-to-submit-reports
- Library for Python: https://github.com/2captcha/2captcha-python