Was this helpful?
How to solve Turnstile on poczta.o2.pl
Technical engineer
poczta.o2.pl is the o2.pl webmail. Its login form is protected by Cloudflare Turnstile: until the captcha is solved, you cannot sign in.
The widget is loaded by the Cloudflare script in explicit mode — the page decides when to render it and does so on the login form. The token is returned into a hidden form field. This site has one quirk: the token field is not named the usual way. The default name in Turnstile is cf-turnstile-response, but here the form expects the token in a field named X-Recaptcha. This is not the site improvising: Turnstile has a built-in response-field-name option, and o2.pl uses it to rename the field. The field is created by the widget, and its identifier changes on every render, so you have to address the field by name.
Before the login form, the site also shows a data-consent dialog. It has nothing to do with Turnstile. The form fields are already in the markup behind that dialog, but you cannot click or fill them until the consent dialog is closed.
Task parameters
The task is created with a createTask request. It carries a task object with these parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | TurnstileTaskProxyless or TurnstileTask |
| websiteURL | String | Yes | Full address of the login page: https://poczta.o2.pl/login/login.html |
| websiteKey | String | Yes | Turnstile sitekey. On this page it is 0x4AAAAAAAgDIEpfeVYsWUsz |
| action | String | No | Value of the action parameter of the turnstile.render call, if it is set. Not required on this site |
| data | String | No | Value of the cData parameter of the turnstile.render call, if it is set. Not required on this site |
| pagedata | String | No | Value of the chlPageData parameter. Needed for Cloudflare Challenge pages. Not required on this site |
| userAgent | String | No | Browser User-Agent. For TurnstileTaskProxyless the service uses its worker's User-Agent and returns it in the response |
If you need to solve the captcha from your own IP address, use the TurnstileTask type and add the proxy details: proxyType, proxyAddress, proxyPort, proxyLogin and proxyPassword.
How to find parameters
Open the login page and close the consent dialog to see the form. Press F12 and, on the Elements tab, find the hidden form fields. The widget here is drawn by a turnstile.render() call with a settings object, so there is no usual data-sitekey attribute on the page. The key sits in two places: in the config in the page source (TURNSTILE_SITEKEY) and in the hidden form field X_Recaptcha-SiteKey:
html
<input type="hidden" name="X_Recaptcha-SiteKey" value="0x4AAAAAAAgDIEpfeVYsWUsz">
<input type="hidden" name="X-Recaptcha" id="cf-chl-widget-qm825_response">
The o2.pl sitekey at the time of writing is 0x4AAAAAAAgDIEpfeVYsWUsz.
Pay attention to the X-Recaptcha field — this is where the token goes. Its id is of the form cf-chl-widget-XXXXX_response and changes on every render, so in a script look the field up by the name X-Recaptcha, not by id.
Code Examples
Python + requests
Sending the task and polling for the result with no extra libraries.
python
import time
import requests
API_KEY = "YOUR_API_KEY"
task = {
"type": "TurnstileTaskProxyless",
"websiteURL": "https://poczta.o2.pl/login/login.html",
"websiteKey": "0x4AAAAAAAgDIEpfeVYsWUsz",
}
created = requests.post(
"https://api.2captcha.com/createTask",
json={"clientKey": API_KEY, "task": task},
timeout=30,
).json()
if created.get("errorId") != 0:
raise SystemExit(f"createTask error: {created.get('errorDescription')}")
task_id = created["taskId"]
print(f"Task created, id {task_id}")
for _ in range(24):
time.sleep(5)
result = requests.post(
"https://api.2captcha.com/getTaskResult",
json={"clientKey": API_KEY, "taskId": task_id},
timeout=30,
).json()
if result.get("errorId") != 0:
raise SystemExit(f"getTaskResult error: {result.get('errorDescription')}")
if result.get("status") == "ready":
print("Token:", result["solution"]["token"])
break
else:
raise SystemExit("The task was not solved within the time limit")
A Turnstile token is a long string that starts with 1. It has to be written into the X-Recaptcha field, as shown below.
Python + Playwright
The example opens the page, closes the consent dialog, reads the sitekey from the page, sends the task and writes the token into the X-Recaptcha field. Put in your own login and password.
python
import os
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = os.getenv("APIKEY_2CAPTCHA", "YOUR_API_KEY")
TARGET_URL = "https://poczta.o2.pl/login/login.html"
LOGIN = "YOUR_LOGIN"
PASSWORD = "YOUR_PASSWORD"
def solve(task):
created = requests.post(
"https://api.2captcha.com/createTask",
json={"clientKey": API_KEY, "task": task},
timeout=30,
).json()
if created.get("errorId") != 0:
raise RuntimeError(f"createTask error: {created.get('errorDescription')}")
task_id = created["taskId"]
print(f"Task created, id {task_id}")
for _ in range(24):
time.sleep(5)
result = requests.post(
"https://api.2captcha.com/getTaskResult",
json={"clientKey": API_KEY, "taskId": task_id},
timeout=30,
).json()
if result.get("errorId") != 0:
raise RuntimeError(f"getTaskResult error: {result.get('errorDescription')}")
if result.get("status") == "ready":
return result["solution"]["token"]
raise RuntimeError("The task was not solved within the time limit")
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
try:
page.goto(TARGET_URL)
# Close the consent dialog if it appeared
consent = page.get_by_role("button", name="Akceptuję i przechodzę do serwisu")
if consent.count() > 0:
consent.first.click()
# The fields are hidden (type=hidden), so wait for state attached, not visible
page.wait_for_selector('input[name="X-Recaptcha"]', state="attached", timeout=30000)
website_key = page.get_attribute('input[name="X_Recaptcha-SiteKey"]', "value")
print("Sitekey from the page:", website_key)
token = solve({
"type": "TurnstileTaskProxyless",
"websiteURL": TARGET_URL,
"websiteKey": website_key,
})
print("Token received:", token[:30], "…")
page.fill("#login", LOGIN)
page.fill("#password", PASSWORD)
page.evaluate("""(token) => {
const field = document.querySelector('input[name="X-Recaptcha"]');
if (!field) {
throw new Error('The X-Recaptcha field is not on the page');
}
field.value = token;
// Submit the form directly, not by clicking the "Zaloguj się" button:
// the button checks the widget state, while form.submit() sends the fields as they are
field.form.submit();
}""", token)
print("Token is in place, the form has been submitted")
except Exception as e:
print(f"Error: {e}")
finally:
browser.close()
Both hidden fields of this form, X-Recaptcha and X_Recaptcha-SiteKey, have type hidden and will never become visible. If you wait for them with page.wait_for_selector without state="attached", the call always times out: by default Playwright waits for a visible element. That is why the example uses state="attached".
How to use the received token
The token from solution.token is written into the value of the hidden field named X-Recaptcha. There is no standard cf-turnstile-response field on this page, so writing the token there does nothing — it has to be the X-Recaptcha field.
But writing it into the field is not enough. Before submitting, the "Zaloguj się" button checks the widget's internal state, not the field value: if you just write the token and click the button, the form raises "Musisz potwierdzić, że jesteś człowiekiem" and does not submit. The workaround is to submit the form directly, bypassing the button handler:
javascript
document.querySelector('input[name="X-Recaptcha"]').value = "RECEIVED_TOKEN";
document.querySelector('form').submit();
A native form.submit() sends the fields as they are, including X-Recaptcha — the same thing the site does internally once the check passes. The form is submitted by POST to /login/v2/sso/preauth.
Along with the token, the service returns a solution.userAgent field — the User-Agent the token was issued under. Turnstile binds the token to the browser, so the sign-in request is safer sent with the same User-Agent that came back in the response. For the TurnstileTaskProxyless type you cannot set your own User-Agent in the task: the service solves the captcha under its worker's User-Agent and returns that one — use exactly that value.
Testing in sandbox mode
Before building the call into a script, the parameters can be checked in sandbox mode. The captcha then goes back to you instead of to the workers of the service.
- Read the sitekey from the page and send the task through createTask right away.
- Open the sandbox settings, switch the role to worker and log in to the application with the key of that role.
- If the Turnstile widget opens and can be solved, the sitekey was read correctly.
Turn the mode off after the check, otherwise new tasks will keep coming to you instead of to the workers.
Common Errors and Solutions
| Error or problem | Cause | Solution |
|---|---|---|
| The token is received, but the form does not accept it | The token was written into the standard cf-turnstile-response field, which does not exist here | Write the token into the field named X-Recaptcha |
| The script cannot find the field by id | The field's id, of the form cf-chl-widget-XXXXX_response, changes on every render | Look the field up by the name X-Recaptcha, not by id |
| The script hangs waiting for the X-Recaptcha field | The field is hidden, and Playwright waits for a visible element by default | Add state="attached" to wait_for_selector |
| Clicking the login button gives "Musisz potwierdzić, że jesteś człowiekiem" | The form checks the widget's internal state, not the field value | Submit the form directly: form.submit() |
| The login page does not open, the consent dialog stays up | The data-consent dialog was not closed | Close the consent dialog, after that the login form fields become usable |
The full list of error codes is on the Error codes page, linked below.
Useful Links
- Cloudflare Turnstile API documentation: https://2captcha.com/api-docs/cloudflare-turnstile
- Cloudflare Turnstile bypass service: https://2captcha.com/p/cloudflare-turnstile
- Sandbox for testing the API: https://2captcha.com/setting#sandbox
- Error codes: https://2captcha.com/api-docs/error-codes
- Using proxies: https://2captcha.com/api-docs/proxy
- Python SDK on GitHub: https://github.com/2captcha/2captcha-python
- More captcha bypass examples for specific sites: https://2captcha.com/h?category=sites