FCaptcha v1.12: Catch AI Agents in Real Browsers
How FCaptcha v1.11 and v1.12 detect AI agents that drive real browsers, using CDP input forensics, think-time cadence, and declared-agent matching.
bot-detectionFCaptcha v1.3 adds 7 biometric keystroke metrics, Playwright detection, AI agent bypass fixes, and server-side PoW validation.
WebDecoy Team
WebDecoy Security Team
FCaptcha v1.3 represents the biggest detection upgrade since the initial release. Three releases — v1.2.0, v1.2.1, and v1.3.0 — landed in rapid succession, each closing gaps that real-world bot operators were exploiting.
The headline: FCaptcha now analyzes how you type, not just how you move your mouse. Seven statistical metrics examine keystroke timing to catch bots that add timing jitter to appear human. Combined with new Playwright-specific detection and a patched AI agent bypass, FCaptcha v1.3 pushes the detection signal count past 50.
GitHub: github.com/webdecoy/fcaptcha Demo: webdecoy.com/product/fcaptcha-demo
After FCaptcha’s initial release, we observed three bypass patterns in the wild:
Zero-movement clicks — AI agents like Manus were clicking the checkbox without generating any mouse movement. Because all behavioral checks required minimum trajectory lengths to trigger, zero-movement interactions slipped through silently.
Playwright stealth — Playwright’s stealth plugins delete navigator.webdriver and suppress standard automation flags. Existing WebDriver detection missed these configurations entirely.
Timing jitter bots — Sophisticated bots were adding random delays between keystrokes to mimic human typing rhythm. FCaptcha’s existing form analysis only checked average typing speed, which jitter bots passed easily.
Each release addressed one of these gaps.
The most critical fix. AI agents were bypassing FCaptcha by programmatically clicking the checkbox with zero mouse trajectory. The scoring logic required minimum mouse data to trigger — so no mouse data meant no penalty.
Zero mouse movement is now flagged as a high-confidence bot signal:
Touch users and keyboard-only users are explicitly exempt from mouse-movement checks:
touchEvents > 0) bypass mouse-movement scoringA touchstart listener was also added to the checkbox widget, which previously only listened for touchmove and missed simple taps.
A new _detectPlaywright() method in the client-side EnvironmentalCollector checks for:
__pw* / __playwright* globals — Playwright injects these window properties during automationnavigator.webdriver — Playwright stealth deletes the webdriver property from the Navigator prototype. Real browsers always have it defined.navigator.webdriver — If the property descriptor shows configurable: true, it has been tampered withchrome.runtime — Chrome-based browsers always expose chrome.runtime. Playwright with Chromium often lacks it.Server-side scoring weights these signals heavily:
| Signal | Score |
|---|---|
playwright_globals | 0.95 |
webdriver_deleted | 0.80 |
webdriver_configurable | 0.70 |
chrome_runtime_missing | 0.60 |
Previously, proof-of-work timing was measured client-side only — easily spoofable. v1.2.1 adds server-side elapsed time measurement. If the server calculates that the PoW was solved in under 1,500ms (impossibly fast for the given difficulty), the result is flagged.
Additionally, PoW is now mandatory. A missing PoW solution triggers a hard-fail with score 0.9 and confidence 0.95, up from the previous lenient 0.5-0.6 penalty.
The original accessibility exemptions were too permissive:
>= 3 (was > 0)>= 2 (was > 0)A single synthetic touchstart or keydown event no longer bypasses behavioral analysis.
The largest feature addition. FCaptcha now performs deep statistical analysis of keystroke timing patterns through seven biometric metrics.
Existing form analysis checked average typing speed and interval variance — two metrics that jitter bots defeat by adding Math.random() * delay between keystrokes. Real human typing has far more complex statistical properties that are hard to simulate:
1. Dwell Variance Measures consistency in how long keys are held down. Humans show natural variation in dwell times based on finger mechanics. Bots using dispatchEvent or sendKeys produce unnaturally consistent dwell durations.
2. Log-Normal Fit Applies a Kolmogorov-Smirnov test to compare the distribution of inter-keystroke intervals against the expected human log-normal distribution. Human typing intervals follow a log-normal curve; synthetic intervals tend toward uniform or normal distributions.
3. Uniformity Detection Specifically catches Math.random()-based jitter. When bots add random delays using uniform random number generators, the interval distribution is detectable as uniform rather than log-normal.
4. Lag-1 Autocorrelation Evaluates sequential timing dependencies. In human typing, the time between keystroke N and N+1 correlates with the time between N+1 and N+2 — your typing rhythm carries momentum. Bots with independent random delays show near-zero autocorrelation.
5. Burst Regularity Analyzes variation in the pauses between typing bursts. Humans type in bursts separated by irregular thinking pauses. Bots tend to type at a steady pace or with artificially regular pause intervals.
6. Shannon Entropy Quantifies the information content within the interval distribution. Human typing produces moderate entropy — neither perfectly ordered nor perfectly random. Bots producing uniform random intervals show high entropy; bots with fixed intervals show low entropy.
7. Rollover Rate Detects overlapping keypresses where one key is pressed before the previous key is released. This is common in fast human typists but rare in automation frameworks that send discrete key events sequentially.
Keystroke cadence analysis is gated conservatively:
botScore > 0.55)The FormAnalyzer class now tracks additional keystroke data per textarea:
Modifier keys (Shift, Control, Alt, Meta, CapsLock) are excluded from dwell and rollover tracking to avoid skewing biometric measurements.
All three server implementations (Node.js, Python, Go) received:
analyzeKeystrokeCadence() function called from analyzeFormInteraction()The overall scoring weights were rebalanced across releases:
| Category | v1.1 | v1.3 |
|---|---|---|
| Behavioral | 40% | 35% |
| Environmental | 35% | 30% |
| Temporal | 15% | 15% |
| Form & Keystroke | 10% | 20% |
The increased weight on form and keystroke signals reflects their improved accuracy after the cadence analysis addition.
Three common bypass strategies are now closed:
The combination of mandatory PoW with server-side timing, 50+ behavioral signals, and biometric keystroke analysis makes FCaptcha significantly harder to bypass at scale.
FCaptcha is fully open source and self-hosted. No external dependencies, no data sharing.
<div id="captcha"></div>
<script src="/fcaptcha.js"></script>
<script>
FCaptcha.render('captcha', {
siteKey: 'your-site-key',
callback: (token) => {
fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({ token })
});
}
});
</script>Choose your backend:
server-go/ — High-performance, production-readyserver-python/ — Flask-based, easy to customizeserver-node/ — Express-based, JavaScript ecosystemAll three implementations include the full detection pipeline: behavioral scoring, environmental analysis, PoW verification, and keystroke cadence analysis.
See FCaptcha in action on our interactive demo page. Test both checkbox and invisible modes with real-time scoring.
FCaptcha development continues in the open. Planned areas of investigation include:
Follow development on GitHub or try FCaptcha on your own infrastructure.
How FCaptcha v1.11 and v1.12 detect AI agents that drive real browsers, using CDP input forensics, think-time cadence, and declared-agent matching.
bot-detectionOpen source CAPTCHA with 40+ behavioral signals, proof of work, and vision AI detection. Self-hosted servers in Go, Python, Node.js.
bot-detectionWebDecoy Node SDK v0.3.0 ships a self-hosted proof-of-work captcha and an in-process detection engine that scores ~40 signals with no third-party calls.
bot-detectionLike this post? Share it with your friends!
Get a personalized demo from our team.