Wait for the condition your test actually needs—not an arbitrary delay. For a visible reCAPTCHA widget, wait for its iframe; when frame creation is the signal, use Puppeteer’s frame wait. If you own the application, an app-controlled readiness hook or Google’s test keys is more reliable than depending on Google’s changing production markup.
await page.waitForSelector('iframe[src*="recaptcha"]', {
timeout: 10_000,
});
Or, when your test needs the frame object:
const captchaFrame = await page.waitForFrame(
frame => frame.url().includes('recaptcha'),
{ timeout: 10_000 },
);
These waits detect an observable state; they do not—and should not—attempt to solve or bypass an anti-abuse challenge.
Choose the state that means “reCAPTCHA is ready”
Google reCAPTCHA integrations differ. A v2 checkbox commonly creates a cross-origin iframe, while invisible v2 and v3 may execute scripts and callbacks without showing a checkbox at all. Start by defining what the test must observe:
- Element presence or visibility: use
page.waitForSelector()when a stable host-page element or expected iframe is the signal. - Frame creation: use
page.waitForFrame()when the test needs to inspect or coordinate with a matching frame. - Application readiness: prefer a container, callback, network-independent test hook, or other element your own code controls.
Puppeteer’s Page API documents both wait methods: Page API documentation. A selector evaluated on the main document does not search inside a cross-origin iframe, so wait for the iframe first and then use the frame object only for operations the browser security model permits.
Recommended Free Tools
#1 Best Overall
- Security Key : Protect your online accounts against unauthorized access by using FIDO2 and U2F authentication with T110. It's the world's most protective security key that works with windows, Mac OS, Linux as well as Chrome, Firefox, Edge and many other major browsers.
- Certified with the new FIDO2 standard, T110 provides the benefit of fast login and strong protection against phishing, account takeover as well as many other online attactks.
- Works with : Bank of America, Github, Google, Microsoft, DUO, Twitter, Facebook, Dropbox, Apple, ebay, BINANCE, mor and more.
- Fits USB-A port : Insert the T110 security key into the USB-A port of each service and log in conveniently with one touch
- For the driver download and user guide, please visit TrustKey Solutions Home support page.
Wait for a visible widget with waitForSelector()
For a v2 checkbox-style integration, this is the smallest useful test:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
try {
await page.goto('https://your-owned-site.example/form', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
const iframe = await page.waitForSelector(
'iframe[src*="recaptcha"]',
{ visible: true, timeout: 10_000 },
);
console.log('Visible reCAPTCHA iframe:', await iframe.evaluate(el => el.src));
} finally {
await browser.close();
}
visible: true asks Puppeteer to wait until the matching node is present and has a visible layout. Omit it when existence, rather than visibility, is the requirement. The timeout is a test boundary: if no match appears in 10 seconds, Puppeteer throws a timeout error that should be reported as a meaningful failure.
Make the selector fit your integration
iframe[src*="recaptcha"] is a practical example, not a universal contract. Google or an integration can change generated attributes, use a different host, or avoid a visible iframe entirely. If your page owns a stable wrapper, wait for that instead:
await page.waitForSelector('[data-testid="captcha-ready"]', {
visible: true,
timeout: 10_000,
});
A host-page marker is less coupled to third-party markup. Add it in the application’s test configuration or expose it from the callback that your form already uses.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWait for the frame with waitForFrame()
Use a frame predicate when creation of a reCAPTCHA frame is the event under test:
Rank #2
- Ultra-Compact FIDO2 Security Key - Plug-and-stay or carry on a keychain. This USB-A hardware security key offers portable, always-on protection for desktop and mobile use. (Item Size: 0.75 X 0.74 IN x 0.25 IN)
- USB-A Hardware Key for All Devices - Works with USB-A ports on PC, Mac, Android, and other laptop/notebook device. Enables secure, cross-platform login with FIDO2.0 passkey support.
- FIDO Certified Security Key - Meets FIDO and FIDO2 standards. Works with Google, Microsoft, GitHub, Dropbox, and more. Please check service compatibility before purchase.
- Passwordless Login with Passkey - Supports passkey login via WebAuthn and CTAP2. Enjoy password-free sign-ins where supported. Not all websites or services currently support passkeys.
- Advanced Multi-Factor Authentication - Offers 200 FIDO2 passkey slots and 50 OATH-TOTP slots. Strong, flexible 2FA/MFA support across various apps and authentication platforms.
const captchaFrame = await page.waitForFrame(
frame => frame.url().includes('recaptcha'),
{ timeout: 10_000 },
);
console.log('Captcha frame appeared:', captchaFrame.url());
This expresses the condition directly and avoids racing a later lookup through page.frames(). Keep the predicate narrow enough for your page; a site can load more than one Google frame. If multiple frames are expected, collect them and identify the one associated with your form rather than assuming the first match.
Selector wait versus frame wait
| Need | Recommended wait | Main caveat |
|---|---|---|
| Confirm a visible checkbox or host element | page.waitForSelector() |
Generated third-party selectors can change. |
| Know that a matching iframe was created | page.waitForFrame() |
A frame can exist without a visible challenge. |
| Confirm your application finished setup | Owned callback, container, or test hook | Requires a small test-facing integration signal. |
Neither method guarantees that a challenge will appear. A route may use invisible v2 or v3, trigger the widget only after a user action, or be configured not to render it in the current environment.
Handle asynchronous script loading correctly
Loading the reCAPTCHA script and rendering the widget are separate events. Google’s loading guidance says functions must not be called until the script has finished loading and documents grecaptcha.ready() plus a v2 onload callback pattern. See Google’s “Loading reCAPTCHA” guide (updated 2025-05-08 UTC).
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsFor an application you control, coordinate the page and the test around the application’s callback or container. Do not treat networkidle as “CAPTCHA ready”: analytics, long polls, ads, and other resources can keep the network busy, while a widget may be ready before the network becomes idle.
// In your owned page, expose a test-only marker from the integration callback.
window.onCaptchaRendered = () => {
document.querySelector('#captcha-container')
?.setAttribute('data-captcha-ready', 'true');
};
// In Puppeteer, wait for that application-owned state.
await page.waitForSelector(
'#captcha-container[data-captcha-ready="true"]',
{ timeout: 10_000 },
);
Keep such hooks out of production behavior or guard them with your normal test-environment configuration.
Rank #3
- USB-C or tap via NFC for easy authentication on any compatible device. No drivers needed; optional Kensington software available for advanced management features.
- Works across Windows, macOS, iOS, Android, ChromeOS, and supports Passkeys and Apple ID.
- Slim, keychain-ready form for easy carry and on-the-go authentication
- IP68-rated for dependable performance
- FIDO CTAP 2.1 for enhanced security features (e.g. resident credentials, Passkey support) and backwards compatibility with CTAP 2. FIDO2 L2 certified security for phishing resistant protection against identity theft and unauthorized access.
Use Google’s supported test configuration for your own site
Production reCAPTCHA is an anti-abuse service, so a test should not depend on receiving a real challenge. Google’s reCAPTCHA FAQ advises separate keys for testing. For v2, Google provides test keys under which no CAPTCHA is shown and verification requests pass; the widget displays a warning so those keys are not mistaken for production credentials. For v3, create a separate testing key and interpret scores cautiously: Google warns that v3 scores may not be accurate because the service relies on real traffic.
With a v2 test key, your correct assertion may be that the form can submit and the server accepts the verification response—not that an iframe appears. If the purpose of a test is specifically to exercise a visible widget, use a controlled integration or staging configuration that renders one, then apply the selector or frame wait above.
Why a wait times out—and what to check
The route never renders a visible iframe
Invisible v2 and v3 commonly do not present a checkbox. Confirm the site’s version and trigger conditions. Wait for the callback, host container, or form state instead of increasing a sleep.
The widget is rendered only after an action
Perform the same authorized action a user would, then wait:
await page.click('button[type="submit"]');
await page.waitForSelector('iframe[src*="recaptcha"]', {
visible: true,
timeout: 10_000,
});
If submission intentionally opens the challenge, assert the challenge state before asserting the final server response.
Rank #4
- Security Key : Protect your online accounts against unauthorized access by using FIDO2 and U2F authentication with T120. It's the world's most protective security key that works with windows, Mac OS, Linux as well as Chrome, Firefox, Edge and many other major browsers.
- Certified with the new FIDO2 standard, T120 provides the benefit of fast login and strong protection against phishing, account takeover as well as many other online attactks.
- Works with : Bank of America, Github, Google, Microsoft, DUO, Twitter, Facebook, Dropbox, Apple, ebay, BINANCE, mor and more.
- Fits USB-C port : Insert the T120 security key into the USB-C port of each service and log in conveniently with one touch
- For the driver download and user guide, please visit TrustKey Solutions Home support page.
The selector matches nothing
Inspect the DOM and frame list in a failing test. Check for a changed integration, a different URL, or a test key that deliberately suppresses the widget. A selector on the main page cannot query elements inside a cross-origin frame; wait for the frame and use its Frame object where appropriate.
The script or callback is not ready
Verify that the script loaded, that the callback name is registered before the script requests it, and that your page calls grecaptcha.ready() or the documented v2 onload flow. A longer fixed delay masks this race and makes tests slower without making them deterministic.
Google shows an automated-query warning
Follow Google’s troubleshooting guidance for that message at “My computer is sending automated queries”. Do not present automated solving or bypass techniques as a Puppeteer fix. Keep browser automation limited to sites and environments you own or are authorized to test.
The wait is flaky in CI
- Use a realistic but bounded timeout and record a screenshot, URL, console output, and frame URLs when it fails.
- Wait for the application state that matters, not global network idleness.
- Use a dedicated staging origin and Google test keys where possible.
- Avoid parallel tests sharing mutable CAPTCHA configuration or session cookies.
- Keep browser and Puppeteer versions consistent across local and CI runners.
Timeouts, retries, and assertions
Choose the timeout from the page’s documented behavior and CI conditions; 10 seconds is an example, not a guarantee. A timeout should identify which state was absent. Do not automatically retry a challenge wait until it “passes”: retries can hide a broken integration and can produce unnecessary traffic to an anti-abuse service.
try {
await page.waitForFrame(
frame => frame.url().includes('recaptcha'),
{ timeout: 10_000 },
);
} catch (error) {
const frames = page.frames().map(frame => frame.url());
console.error('reCAPTCHA frame did not appear', { frames });
throw error;
}
If your acceptance criterion is successful form verification, assert the server-side result or your application’s completion state. Frame appearance is only the right assertion when frame appearance itself is what the test promises.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Best Value
Or skip the browser setup
If you need a clean image or PDF of a page rather than a test of your own CAPTCHA integration, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
Use it only for pages you are allowed to capture; it is not a CAPTCHA-solving service. The API call is documented at ScreenshotNeo’s documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Every plan includes its capture options, including full-page and element shots, device and viewport controls, custom headers and cookies, waits, blocking rules, caching, PDFs, async jobs, bulk capture, and usage reporting. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Further reading
- Puppeteer Page API for current wait method signatures.
- Google reCAPTCHA FAQ for test keys and version-specific guidance.
- Google’s loading guide for asynchronous initialization.
- Puppeteer issue #5245, opened 2019-12-11, which records the original “wait for a Recaptcha to load” phrasing but is not a substitute for current API documentation.
Frequently Asked Questions
Can I wait for a CAPTCHA by sleeping for five seconds?
You can, but a fixed sleep is nondeterministic. A state-based selector, frame, or application callback wait reports the condition your test actually needs and fails sooner when configuration is wrong.
Does waiting for the iframe prove that reCAPTCHA passed?
No. It proves only that a matching frame was created (and, with a visible selector wait, that it is visible). Verification must be asserted through your application’s documented success state or server response.
Should production CAPTCHA keys be used in CI?
For an owned application, use separate Google test keys and a staging configuration. Google’s v2 test keys suppress the challenge and pass verification; v3 testing scores may be inaccurate.
The Bottom Line
Use waitForSelector() for a visible, stable element, waitForFrame() for frame creation, and an application-owned callback whenever you control the page. Treat a timeout as evidence about the integration—not an invitation to add a longer sleep or bypass an anti-abuse challenge.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




