Tutorials

reCAPTCHA in Single Page Applications: Dynamic Loading Patterns

Single page applications load reCAPTCHA dynamically — the widget doesn't exist in the initial HTML. A React login form renders the CAPTCHA only when the component mounts. A Vue checkout page loads reCAPTCHA after the user clicks "Place Order." Traditional page-source scraping misses these entirely. Here's how to detect and solve dynamically loaded reCAPTCHAs.

Why SPAs Are Different

Traditional page SPA
reCAPTCHA script in initial HTML Script injected after route change
Widget renders on page load Widget renders on component mount
Site key in page source Site key in JavaScript bundle
Form submits via POST Form submits via XHR/fetch

In a SPA, the reCAPTCHA widget may not exist until a specific user action triggers it. Your automation must wait for the widget to appear.

Detecting the reCAPTCHA Widget

Wait for the Element

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com/login")

    # SPA may need a click or navigation to trigger reCAPTCHA
    page.click("#show-login-form")

    # Wait for reCAPTCHA iframe to appear
    recaptcha_frame = page.wait_for_selector(
        "iframe[src*='recaptcha']",
        timeout=15000
    )
    print("reCAPTCHA detected:", recaptcha_frame.get_attribute("src"))

Extract the Site Key

The site key can be in multiple locations in a SPA:

# Method 1: From the iframe src
iframe_src = recaptcha_frame.get_attribute("src")
# src contains: ...?k=6LcR_RsTAAAAADge...
import re
match = re.search(r'[?&]k=([^&]+)', iframe_src)
site_key = match.group(1) if match else None

# Method 2: From data-sitekey attribute
site_key = page.eval_on_selector(
    "[data-sitekey]",
    "el => el.getAttribute('data-sitekey')"
)

# Method 3: From JavaScript bundle (last resort)
site_key = page.evaluate("""
    () => {
        // Check for grecaptcha render calls
        const scripts = document.querySelectorAll('script');
        for (const s of scripts) {
            const match = s.textContent.match(/sitekey['":\s]+(['"])(6L[^'"]+)\\1/);
            if (match) return match[2];
        }
        return null;
    }
""")

Solving the reCAPTCHA

Once you have the site key, submit to CaptchaAI:

import requests
import time

def solve_recaptcha(site_key, page_url):
    # Submit task
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    # Poll for result
    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]
    raise TimeoutError("Solve timed out")

Injecting the Token in a SPA

SPAs don't submit traditional forms. You need to inject the token where the application expects it.

Method 1: Set the Hidden Textarea

token = solve_recaptcha(site_key, "https://example.com/login")

# Inject into the g-recaptcha-response textarea
page.evaluate(f"""
    document.getElementById('g-recaptcha-response').value = '{token}';
""")

# Submit the form
page.click("#login-button")

Method 2: Trigger the Callback

Many SPA reCAPTCHA implementations use a callback function:

# Find the callback function name
callback = page.evaluate("""
    () => {
        const widget = document.querySelector('.g-recaptcha');
        return widget?.getAttribute('data-callback') || null;
    }
""")

# Call it with the token
if callback:
    page.evaluate(f"window['{callback}']('{token}')")
else:
    # Try the default grecaptcha callback
    page.evaluate(f"""
        if (window.grecaptcha) {{
            // Set the response and trigger verification
            document.getElementById('g-recaptcha-response').value = '{token}';
            // Find and call any registered callbacks
            const form = document.querySelector('form');
            if (form) form.dispatchEvent(new Event('submit'));
        }}
    """)

Method 3: Intercept the XHR (JavaScript / Puppeteer)

const puppeteer = require('puppeteer');

async function solveRecaptchaInSPA() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();

  // Intercept the API call and inject the token
  await page.setRequestInterception(true);
  page.on('request', request => {
    if (request.url().includes('/api/login')) {
      const postData = JSON.parse(request.postData() || '{}');
      // Token already set via page.evaluate — let it pass
      request.continue();
    } else {
      request.continue();
    }
  });

  await page.goto('https://example.com/login');
  await page.waitForSelector('[data-sitekey]');

  const siteKey = await page.$eval(
    '[data-sitekey]',
    el => el.getAttribute('data-sitekey')
  );

  // Solve with CaptchaAI (implementation omitted — same as Python)
  const token = await solveCaptcha(siteKey, page.url());

  // Inject token and trigger callback
  await page.evaluate((t) => {
    document.getElementById('g-recaptcha-response').value = t;
    const callback = document.querySelector('.g-recaptcha')
      ?.getAttribute('data-callback');
    if (callback && window[callback]) {
      window[callback](t);
    }
  }, token);
}

Framework-Specific Patterns

React (react-google-recaptcha)

React apps often use the react-google-recaptcha package. The component renders asynchronously:

# Wait for React to mount the component
page.wait_for_selector(".g-recaptcha", state="attached")

# The sitekey is in the rendered div's data attribute
site_key = page.eval_on_selector(
    ".g-recaptcha", "el => el.dataset.sitekey"
)

Vue (vue-recaptcha)

# Vue may use v-if to conditionally render
# Navigate or interact to trigger the condition
page.click("#proceed-to-checkout")
page.wait_for_selector("iframe[src*='recaptcha']")

Angular

# Angular apps may lazy-load reCAPTCHA modules
# Wait for the specific Angular component
page.wait_for_selector("re-captcha, app-recaptcha, [data-sitekey]")

Handling Route Changes

SPAs reuse the page — navigation happens without full reloads:

# Listen for reCAPTCHA appearing after SPA navigation
page.goto("https://example.com")

# Navigate within the SPA
page.click("a[href='/login']")

# The URL changed but no page reload happened
# Wait for the CAPTCHA to render in the new "page"
page.wait_for_selector("iframe[src*='recaptcha']", timeout=10000)

Troubleshooting

Issue Cause Fix
g-recaptcha-response textarea not found SPA hasn't rendered the widget yet Use wait_for_selector with adequate timeout
Token injected but form doesn't submit Callback not triggered Find and call the data-callback function
Site key not in page source Bundled in JS or loaded dynamically Wait for widget render, then extract from iframe src
Token works once then fails SPA re-renders component, clearing token Inject token immediately before form submission
Widget re-renders after token injection React/Vue reactivity clears the value Use data-callback approach instead of setting textarea

FAQ

Can I skip the browser and solve SPA reCAPTCHAs with just HTTP requests?

If you can extract the site key and replicate the form submission API call, yes. Many SPA forms submit via a REST API endpoint — you can call it directly with the token. But you need a browser to discover the site key and API endpoint first.

How do I handle reCAPTCHA that only appears on certain user actions?

Automate the triggering action (click a button, fill a form, navigate to a route), then wait for the reCAPTCHA element to appear. Use wait_for_selector with a reasonable timeout.

Does CaptchaAI care whether the reCAPTCHA is in a SPA?

No. CaptchaAI only needs the site key and page URL. How the widget loads on the page doesn't affect solving.

Next Steps

Solve dynamically loaded reCAPTCHAs in any SPA — get your CaptchaAI API key.

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
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
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
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
Tutorials Using Fiddler to Inspect CaptchaAI API Traffic
How to use Fiddler Everywhere and Fiddler Classic to capture, inspect, and debug Captcha AI API requests and responses — filters, breakpoints, and replay for tr...

How to use Fiddler Everywhere and Fiddler Classic to capture, inspect, and debug Captcha AI API requests and r...

Automation Python All CAPTCHA Types
Mar 05, 2026
Tutorials GeeTest Token Injection in Browser Automation Frameworks
how to inject Gee Test v 3 solution tokens into Playwright, Puppeteer, and Selenium — including the three-value response, callback triggering, and form submissi...

Learn how to inject Gee Test v 3 solution tokens into Playwright, Puppeteer, and Selenium — including the thre...

Automation Python Testing
Jan 18, 2026