hCaptcha vs Cloudflare Turnstile: Which reCAPTCHA Alternative Wins?

Both hCaptcha and Cloudflare Turnstile position themselves as the reCAPTCHA replacement. With Google's free tier slashed to 10K assessments/month, PHP developers are choosing between these two.

The core trade-off: Turnstile is invisible and free at scale. hCaptcha's free tier forces visible image challenges on most users, but its Enterprise tier offers features Turnstile can't match. Which matters more depends on your project.

Head-to-Head Comparison

Feature hCaptcha (Free) hCaptcha (Pro $99/mo) Cloudflare Turnstile (Free)
Free tier limit 100K requests/month 500K requests/month 1M requests/month
User experience Image challenges (always visible) Mostly invisible (passive mode) Invisible to the vast majority of users
Challenge rate Most users see challenges ~10-20% see challenges <5% see a brief widget
Bot detection method Image classification + behavioral Risk scoring + behavioral Browser signals + Cloudflare network data
Works in China Yes Yes Limited (Cloudflare availability varies)
On-premise deployment No Enterprise only No
Uptime SLA None None None on free tier
Data collection IP, mouse, browser fingerprint, cookies Same IP, browser signals (claims no cookies)
Headquarters US (Intuition Machines) US US (Cloudflare)
PHP integration effort Easy (cURL POST) Same Easy (cURL POST)
Pricing cliff $99/mo at 100K Custom at 500K ~$2,000/mo (Enterprise Bot Management) beyond 1M

The comparison most articles get wrong: They compare Turnstile (free, invisible) against hCaptcha (free, visible challenges). That's not a fair fight. If you want invisible hCaptcha, you need the $99/month Pro tier. Most reviews don't mention this.

PHP Integration: Nearly Identical

Both use the same server-side pattern. Here's a single function that handles either one:

<?php
// Unified CAPTCHA verification — works with Turnstile and hCaptcha
function verifyCaptcha(string $token, string $secret, string $provider = 'turnstile'): bool
{
    $endpoint = match($provider) {
        'turnstile' => 'https://challenges.cloudflare.com/turnstile/v0/siteverify',
        'hcaptcha'  => 'https://api.hcaptcha.com/siteverify',
    };

    $ch = curl_init($endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query([
            'secret'   => $secret,
            'response' => $token,
            'remoteip' => $_SERVER['REMOTE_ADDR'] ?? '',
        ]),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 5,
        CURLOPT_CONNECTTIMEOUT => 3,
    ]);

    $response = curl_exec($ch);
    $error    = curl_error($ch);
    curl_close($ch);

    if ($response === false) {
        error_log("CAPTCHA API error ({$provider}): {$error}");
        return false;
    }

    $data = json_decode($response, true);
    return $data['success'] ?? false;
}

// Turnstile: token in cf-turnstile-response
$valid = verifyCaptcha($_POST['cf-turnstile-response'] ?? '', getenv('TURNSTILE_SECRET') ?: '', 'turnstile');

// hCaptcha: token in h-captcha-response
$valid = verifyCaptcha($_POST['h-captcha-response'] ?? '', getenv('HCAPTCHA_SECRET') ?: '', 'hcaptcha');

The frontend difference is just the script source and widget class:

<!-- Turnstile -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>

<!-- hCaptcha -->
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<div class="h-captcha" data-sitekey="YOUR_SITE_KEY"></div>

Switching between them is a straightforward API swap: change the JavaScript source, the widget class, the verification URL, and the POST field name. Cloudflare even publishes a step-by-step hCaptcha-to-Turnstile migration guide.

What Matters: The Real Differences

User Experience

This is where Turnstile wins decisively — on the free tier. Turnstile is invisible to the vast majority of users. hCaptcha free shows image challenges to most visitors. Image challenges take 5-10 seconds, and visible CAPTCHAs measurably reduce form completions.

If you're comparing at the same price point (free vs free), Turnstile offers dramatically better UX. hCaptcha only matches Turnstile's invisible experience on the $99/month Pro plan.

Bot Detection

hCaptcha's image challenges force bots to solve visual puzzles — a harder barrier than Turnstile's browser-signal approach. But "harder" is relative when CAPTCHA-solving services like 2Captcha offer both hCaptcha and Turnstile bypass at $0.003-0.05 per solve.

Turnstile relies on Cloudflare's network-level visibility — request patterns, IP reputation, TLS fingerprinting. It sees more signals but asks less of the user. The trade-off is real: a sophisticated bot with a real browser and residential IP will likely pass Turnstile more easily than hCaptcha's image challenges.

Neither is sufficient alone against determined attackers. Both need honeypot fields and rate limiting as additional layers.

Privacy and GDPR

Both are US-based companies subject to FISA Section 702. Neither can guarantee EU data stays in the EU. Articles calling either "GDPR-compliant by default" are oversimplifying.

The practical differences:

Both trigger cookie-consent requirements in jurisdictions that broadly define "tracking." For strict EU/GDPR compliance, consider self-hosted alternatives like ALTCHA that eliminate cross-border data transfers entirely.

Reliability

Neither service offers an SLA on its free tier. Both have had documented outages:

Build a fallback. What happens when the verification API is unreachable? Most PHP implementations default to blocking (fail-closed), which locks out all users during an outage. Decide your strategy in advance:

<?php
// Fail-open strategy: allow submission when CAPTCHA API is down
function verifyCaptchaWithFallback(string $token, string $secret, string $endpoint): bool
{
    $ch = curl_init($endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query([
            'secret' => $secret, 'response' => $token,
        ]),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 5,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // API unreachable — fail-open (accept submission, flag for review)
    if ($response === false || $httpCode !== 200) {
        error_log("CAPTCHA API unreachable — failing open");
        return true; // Accept but flag
    }

    $data = json_decode($response, true);
    return $data['success'] ?? false;
}

Pricing at Scale

Both have pricing cliffs that comparison articles rarely mention:

For a growing site that might exceed free limits, hCaptcha's $99/month Pro tier is much cheaper than Turnstile's Enterprise jump. For sites comfortably under 1M requests/month, Turnstile's free tier is hard to beat.

When to Pick Turnstile

When to Pick hCaptcha

When to Pick Neither

Verdict

For most PHP developers building standard forms — contact pages, login screens, registration flows — Cloudflare Turnstile is the better default. It's free at 10x hCaptcha's volume, invisible to nearly all users, and the PHP integration is trivial.

hCaptcha earns its place when you need visible challenges for compliance, global availability including China, or a smoother pricing path beyond the free tier. But on the free plan, asking users to label images when Turnstile asks them nothing is a hard trade-off to justify.

Whichever you choose, neither is a complete bot protection strategy. Pair either one with layered defenses — honeypots, rate limiting, and monitoring — because CAPTCHA-solving services will bypass both for pennies per solve.