Troubleshooting

CAPTCHA After Form Validation Error: Re-Solving on Page Reload

You solve the CAPTCHA, submit the form, and the server responds: "Invalid email format." The page reloads with validation errors, but the CAPTCHA token is now expired. You need a fresh token, but the form still has your previous input. This loop — validate, fail, re-solve — is one of the most common causes of wasted CAPTCHA solves.

Why Tokens Expire After Form Errors

Situation Token Status Action Needed
Server returns validation error, same page Expired (used once) Re-solve with fresh sitekey
Client-side validation blocks submit Still valid (unused) Reuse if under 120s old
Page full reload on error Expired (new page context) Must re-solve
AJAX form submit, no reload May still be valid Check token age before re-solving
Server rejects token as already used Consumed Must re-solve

Python: Detect and Re-Solve Pattern

import requests
import time
from datetime import datetime, timedelta

API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"

TOKEN_MAX_AGE = 110  # Seconds — reCAPTCHA tokens expire at ~120s


def solve_recaptcha(sitekey, pageurl, cookies=None):
    """Solve a reCAPTCHA and return the token with timestamp."""
    params = {
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }
    if cookies:
        params["cookies"] = cookies

    resp = requests.post(SUBMIT_URL, data=params, timeout=30).json()
    if resp.get("status") != 1:
        raise RuntimeError(f"Submit failed: {resp.get('request')}")

    task_id = resp["request"]
    for _ in range(60):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return {
                "token": poll["request"],
                "created_at": time.monotonic(),
            }
        raise RuntimeError(f"Solve failed: {poll.get('request')}")

    raise RuntimeError("Timeout")


def is_token_fresh(token_data):
    """Check if a token is still usable."""
    if not token_data:
        return False
    age = time.monotonic() - token_data["created_at"]
    return age < TOKEN_MAX_AGE


def submit_form_with_retry(session, form_url, form_data, sitekey, max_retries=3):
    """
    Submit a form with CAPTCHA. Re-solve if validation fails.
    """
    token_data = None

    for attempt in range(1, max_retries + 1):
        # Only solve if token is missing or expired
        if not is_token_fresh(token_data):
            print(f"  Attempt {attempt}: Solving CAPTCHA...")
            token_data = solve_recaptcha(sitekey, form_url)

        # Attach token to form data
        form_data["g-recaptcha-response"] = token_data["token"]

        # Submit the form
        response = session.post(form_url, data=form_data)

        # Check for success
        if response.status_code == 200 and "success" in response.text.lower():
            print(f"  Form submitted successfully on attempt {attempt}")
            return response

        # Check for validation errors (not CAPTCHA errors)
        if "validation" in response.text.lower() or "invalid" in response.text.lower():
            print(f"  Attempt {attempt}: Validation error — fixing form data")

            # Fix form data based on error (site-specific logic)
            # form_data = fix_validation_errors(response.text, form_data)

            # Token was consumed — mark as expired
            token_data = None
            continue

        # Check for CAPTCHA-specific rejection
        if "captcha" in response.text.lower() or "robot" in response.text.lower():
            print(f"  Attempt {attempt}: CAPTCHA rejected — re-solving")
            token_data = None
            continue

        print(f"  Attempt {attempt}: Unexpected response: {response.status_code}")
        token_data = None

    raise RuntimeError(f"Form submission failed after {max_retries} attempts")


# Usage
session = requests.Session()
form_url = "https://example.com/register"
sitekey = "SITE_RECAPTCHA_KEY"

form_data = {
    "email": "user@example.com",
    "password": "securepassword123",
    "name": "Test User",
}

result = submit_form_with_retry(session, form_url, form_data, sitekey)

JavaScript: Re-Solve on Validation Failure

const API_KEY = "YOUR_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
const TOKEN_MAX_AGE_MS = 110_000;

async function solveRecaptcha(sitekey, pageurl) {
  const params = new URLSearchParams({
    key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: "1",
  });
  const resp = await (await fetch(SUBMIT_URL, { method: "POST", body: params })).json();
  if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);

  const taskId = resp.request;
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return { token: poll.request, createdAt: Date.now() };
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

function isTokenFresh(tokenData) {
  if (!tokenData) return false;
  return Date.now() - tokenData.createdAt < TOKEN_MAX_AGE_MS;
}

async function submitWithRetry(formUrl, formData, sitekey, maxRetries = 3) {
  let tokenData = null;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    if (!isTokenFresh(tokenData)) {
      console.log(`  Attempt ${attempt}: Solving CAPTCHA...`);
      tokenData = await solveRecaptcha(sitekey, formUrl);
    }

    formData["g-recaptcha-response"] = tokenData.token;
    const params = new URLSearchParams(formData);
    const response = await fetch(formUrl, { method: "POST", body: params });
    const text = await response.text();

    if (response.ok && text.includes("success")) {
      console.log(`  Submitted on attempt ${attempt}`);
      return text;
    }

    // Validation error — token was consumed
    console.log(`  Attempt ${attempt}: Form error — will re-solve`);
    tokenData = null;
  }

  throw new Error(`Failed after ${maxRetries} attempts`);
}

// Usage
submitWithRetry(
  "https://example.com/register",
  { email: "user@example.com", password: "secure123", name: "Test" },
  "SITE_KEY"
).then(console.log);

Decision Flow: Re-Solve or Reuse?

After form error... Token age < 110s? Token was submitted to server? Action
Client-side validation blocked submit Yes No Reuse token
Client-side validation blocked submit No No Re-solve
Server returned validation error Any Yes Re-solve (consumed)
Network error before response Yes Unknown Re-solve (safer)
AJAX partial form submit Yes Depends Check server logs

Troubleshooting

Issue Cause Fix
"Invalid CAPTCHA" on every retry Token expired between solve and submit Reduce form fill time; solve CAPTCHA last, just before submit
Double-charged for same form Token expired, re-solved but first token wasn't consumed Track token usage — only flag as expired if server received it
Infinite re-solve loop Form always fails for non-CAPTCHA reasons Detect non-CAPTCHA errors separately; don't re-solve for email format issues
Token works on first submit but not after reload Page reload generates new CAPTCHA instance with new data-s parameter Re-extract sitekey and data-s from fresh page source
Rate limited after many re-solves Too many rapid solve requests Add backoff between attempts; fix form data to reduce validation failures

FAQ

How many times can a reCAPTCHA token be submitted?

Once. Google's reCAPTCHA tokens are single-use. After the server verifies a token with Google's siteverify API, that token is consumed — even if the form submission otherwise fails.

Should I pre-solve while fixing form data?

Yes, if your form fix is deterministic and quick. Start the CAPTCHA solve in parallel with form data correction so the fresh token is ready when you re-submit. But don't pre-solve if you're unsure the form needs re-submission.

What about Turnstile tokens after form errors?

Turnstile tokens have a longer validity window (~300 seconds) and some sites allow reuse. Check your specific target — if the server doesn't call the Turnstile verification API until form data validates, the token may survive multiple submission attempts.

Next Steps

Stop wasting CAPTCHA solves on form validation loops — get your CaptchaAI API key and implement smart re-solve logic.

Related guides:

Discussions (0)

No comments yet.

Related Posts

Reference CAPTCHA Token Injection Methods Reference
Complete reference for injecting solved CAPTCHA tokens into web pages.

Complete reference for injecting solved CAPTCHA tokens into web pages. Covers re CAPTCHA, Turnstile, and Cloud...

Automation Python reCAPTCHA v2
Apr 08, 2026
Tutorials Pytest Fixtures for CaptchaAI API Testing
Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI.

Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI. Covers mocking, live integra...

Automation Python reCAPTCHA v2
Apr 08, 2026
Reference Browser Session Persistence for CAPTCHA Workflows
Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and maintain authenticated state.

Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and main...

Automation Python reCAPTCHA v2
Feb 24, 2026
Integrations Browser Profile Isolation + CaptchaAI Integration
Browser profile isolation tools create distinct browser environments with unique fingerprints per session.

Browser profile isolation tools create distinct browser environments with unique fingerprints per session. Com...

Automation Python reCAPTCHA v2
Feb 21, 2026
Tutorials Securing CaptchaAI Credentials in Environment Variables
Store Captcha AI API keys securely using environment variables, .env files, Docker secrets, and cloud secret managers instead of hardcoding.

Store Captcha AI API keys securely using environment variables, .env files, Docker secrets, and cloud secret m...

Automation Python reCAPTCHA v2
Feb 12, 2026
Comparisons WebDriver vs Chrome DevTools Protocol for CAPTCHA Automation
Compare Web Driver and Chrome Dev Tools Protocol (CDP) for CAPTCHA automation — detection, performance, capabilities, and when to use each with Captcha AI.

Compare Web Driver and Chrome Dev Tools Protocol (CDP) for CAPTCHA automation — detection, performance, capabi...

Automation Python reCAPTCHA v2
Mar 27, 2026
Use Cases CAPTCHA Solving in Ticket Purchase Automation
How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automated purchasing workflows.

How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automate...

Automation Python reCAPTCHA v2
Feb 25, 2026
Use Cases Event Ticket Monitoring with CAPTCHA Handling
Build an event ticket availability monitor that handles CAPTCHAs using Captcha AI.

Build an event ticket availability monitor that handles CAPTCHAs using Captcha AI. Python workflow for checkin...

Automation Python reCAPTCHA v2
Jan 17, 2026
Explainers reCAPTCHA v2 Invisible: Trigger Detection and Solving
Detect and solve re CAPTCHA v 2 Invisible challenges with Captcha AI — identify triggers, extract parameters, and handle auto-invoked CAPTCHAs.

Detect and solve re CAPTCHA v 2 Invisible challenges with Captcha AI — identify triggers, extract parameters,...

Automation Python reCAPTCHA v2
Apr 07, 2026
Troubleshooting GeeTest v3 Error Codes: Complete Troubleshooting Reference
Complete reference for Gee Test v 3 error codes — from registration failures to validation errors — with causes, fixes, and Captcha AI-specific troubleshooting.

Complete reference for Gee Test v 3 error codes — from registration failures to validation errors — with cause...

Automation Testing GeeTest v3
Apr 08, 2026
Troubleshooting Turnstile Token Invalid After Solving: Diagnosis and Fixes
Fix Cloudflare Turnstile tokens that come back invalid after solving with Captcha AI.

Fix Cloudflare Turnstile tokens that come back invalid after solving with Captcha AI. Covers token expiry, sit...

Python Cloudflare Turnstile Web Scraping
Apr 08, 2026
Troubleshooting Common GeeTest v3 Errors and Fixes
Diagnose the most common Gee Test v 3 errors — stale challenge, bad parameters, validation failures — and fix them with practical troubleshooting steps.

Diagnose the most common Gee Test v 3 errors — stale challenge, bad parameters, validation failures — and fix...

Automation Testing GeeTest v3
Jan 24, 2026