Token Turnstile bị từ chối gần như luôn là lỗi tích hợp, không phải lỗi lời giải. CaptchaAI trả về chuỗi hợp lệ; Cloudflare loại nó vì bạn gửi muộn, sai sitekey, sai tên trường hoặc lệch session.
Vì vậy, thứ tự chẩn đoán mới là điều quan trọng. Sáu nguyên nhân dưới đây xếp từ dễ loại trừ nhất tới tốn công nhất.
Kiểm tra nhanh trong 60 giây
- Token gửi sau khi nhận bao lâu? Quá 5 phút là hỏng.
- sitekey có đúng của form bạn submit không?
- Tên trường có phải
cf-turnstile-responsekhông? - Load trang và submit cùng session chứ?
- Widget có
data-actionhoặcdata-cdatakhông?
Đối chiếu triệu chứng với nguyên nhân
Khớp hiện tượng với cột bên phải trước khi sửa code.
| Triệu chứng | Nguyên nhân |
|---|---|
| 403 khi gửi token | Token hết hạn |
| Submit không phản hồi | Sai tên trường |
| Nhận token nhưng vẫn bị chặn | Sai sitekey |
| Lần đầu được, sau hỏng | Token dùng lại |
| Trình duyệt được, script không | Thiếu cookie phiên |
Nguyên nhân 1: token hết hạn trước khi kịp gửi
Token Turnstile thường sống 300 giây (5 phút), có nơi ngắn hơn. Rủi ro nằm ở code chạy sau khi nhận token.
- Worker nhận token rồi mới lấy CSRF token.
- Job chờ trong hàng đợi vì rate limit.
- Retry bên ngoài chạy lại cả hàm.
Chuẩn bị sẵn cookie, header và payload, rồi mới gọi giải.
import requests
import time
API_KEY = "YOUR_API_KEY"
# Submit Turnstile task
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": "0x4AAAAAAADnPIDROz1234",
"pageurl": "https://staging.example.com/qa-login",
"json": 1
}).json()
task_id = submit["request"]
time.sleep(10)
# Poll for result
for _ in range(24):
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
# USE TOKEN IMMEDIATELY — do not delay
response = requests.post("https://staging.example.com/qa-login", data={
"username": "user",
"password": "pass",
"cf-turnstile-response": token
})
break
time.sleep(5)
Nếu vòng polling thường xuyên chạm tới lần lặp thứ 24, xem lại thiết lập timeout theo loại CAPTCHA.
Nguyên nhân 2: sai sitekey
Mỗi widget có sitekey riêng, và một trang thường có nhiều hơn một widget. Lấy đúng cái gắn với form bạn gửi:
// In browser console on the target page
document.querySelectorAll('[data-sitekey]').forEach(el => {
console.log('Sitekey:', el.getAttribute('data-sitekey'));
console.log('Element:', el);
});
Nếu trang chặn bằng màn hình chờ toàn trang thì đó là Cloudflare Challenge, và method tương ứng là cloudflare_challenge.
Nguyên nhân 3: sai tên trường chứa token
Turnstile đọc token ở cf-turnstile-response. Giữ lại g-recaptcha-response từ script reCAPTCHA cũ là lỗi copy-paste phổ biến nhất.
# WRONG — this is for reCAPTCHA
data = {"g-recaptcha-response": token}
# CORRECT — this is for Turnstile
data = {"cf-turnstile-response": token}
Nếu trang đổi tên trường, kiểm tra thẳng trên DOM:
// Check what field the Turnstile widget populates
document.querySelector('[name*="turnstile"], [name*="cf-"]')
null: form dùng tên tùy biến, đọc handler submit.- Form JSON: token nằm trong request body.
Nguyên nhân 4: token đã dùng một lần
Token Turnstile dùng một lần. Retry với cùng chuỗi đó chắc chắn hỏng, kể cả khi còn hạn.
- Đặt retry ra ngoài hàm giải để mỗi lần thử có token mới.
- Timeout ở tầng mạng vẫn tính là token đã tiêu.
Nguyên nhân 5: thiếu cookie hoặc lệch session
Cloudflare đối chiếu token với ngữ cảnh phiên: giải ở session này rồi gửi ở session khác thường bị loại.
# Use the SAME session for page load and token submission
session = requests.Session()
# Load the page first to establish cookies
session.get("https://staging.example.com/qa-login")
# Then solve and submit using the same session
token = solve_turnstile(sitekey, pageurl)
session.post("https://staging.example.com/qa-login", data={
"cf-turnstile-response": token
})
Pipeline nhiều tiến trình nên gắn session vào từng tác vụ, không dùng chung client.
Nguyên nhân 6: thiếu action hoặc cData
Một số triển khai gắn action và cData vào token; thiếu chúng trong request giải thì token sẽ lệch.
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": "0x4AAAAAAADnPIDROz1234",
"pageurl": "https://staging.example.com/qa-login",
"action": "login", # If required by the site
"data": "custom_cdata_value", # If required by the site
"json": 1
}).json()
Đọc data-action và data-cdata ngay trên thẻ chứa widget.
Cây quyết định khi token bị từ chối
Đi từ trên xuống, dừng ở nhánh đầu tiên trả lời "không".
Token solved but rejected
↓
Used within 5 minutes? → No → Solve again, submit immediately
↓ Yes
Correct sitekey? → No → Find the correct sitekey from the page
↓ Yes
Using cf-turnstile-response field? → No → Change field name
↓ Yes
Same session for page load + submit? → No → Use session persistence
↓ Yes
Token used only once? → No → Solve a new token per submission
↓ Yes
Site requires action/cData? → Check page source, add to API call
Ví dụ: team QA thuê ngoài tại TP.HCM
Một team QA outsourcing chạy regression ban đêm trên staging có Turnstile. Chạy tay thì qua, chạy trên CI thì hỏng khoảng một nửa số lần.
Lý do là thứ tự bước trong runner: hàm giải chạy sớm, còn submit đợi job seed database 4–6 phút. Đưa nó xuống sát submit là hết lỗi.
- Ghi mốc nhận token và mốc gửi request — chênh lệch là số liệu chính.
- Log độ dài token thay vì cả chuỗi, theo tinh thần Nghị định 13/2023/NĐ-CP.
- Cần mốc so sánh thì chạy lại luồng giải Turnstile qua API.
Câu hỏi thường gặp
Token Turnstile sống được bao lâu?
Thường 300 giây (5 phút), có trang đặt ngắn hơn. Gửi ngay trong vài giây sau khi nhận.
Giải token mới cho mỗi lần thử có tốn thêm tiền không?
Không. CaptchaAI tính theo thread chứ không theo lượt giải: gói BASIC ($15/tháng, 5 thread) có số lượt giải không giới hạn trong tháng.
Có nên cache token Turnstile không?
Không nên. Token dùng một lần và hết hạn nhanh, cache chỉ sinh lỗi khó tái hiện.
Trang chuyển sang hCaptcha thì sao?
CaptchaAI không hỗ trợ hCaptcha và FunCaptcha (Arkose Labs); GeeTest v4 mới sắp ra mắt. Các loại dùng được: reCAPTCHA v2/v3, Turnstile, Cloudflare Challenge, GeeTest v3, image/OCR, grid, BLS.
Lỗi nằm ở token hay ở phần còn lại của request?
Gửi đúng request đó với token lấy tay từ trình duyệt. Vẫn 403 là do header hoặc cookie; qua được thì xem token hết hạn trước khi gửi.
Giải Turnstile bằng CaptchaAI
Lấy API key tại captchaai.com, gửi task turnstile tới in.php và dùng token ngay.