reCAPTCHA v2 vs v3: Which Should You Use in 2026?

With Google's April 2026 pricing change slashing the free tier from 1M to 10K assessments/month, choosing between reCAPTCHA v2 and v3 matters more than ever — because every extra assessment now costs money. Here's what PHP developers need to know.

The short answer: v3 gives better UX when properly tuned, but v2 gives a hard yes/no that's easier to trust. For most PHP developers in 2026, neither is the best choice — Cloudflare Turnstile gives you invisible verification with a 1M/month free tier and no score threshold management.

How They Work: The Fundamental Difference

Feature reCAPTCHA v2 reCAPTCHA v3
User experience Checkbox + image challenges Invisible (runs in background)
Verification model Binary: pass or fail Score: 0.0 (bot) to 1.0 (human)
Developer responsibility Embed widget, verify token Embed JS, verify token, interpret score, decide action
Fallback Increasingly difficult puzzles None — you must build your own
User friction High (image selection takes 10+ seconds) None when working; silent rejection when not
Bot detection approach Challenge-response (hard verification) Behavioral analysis (probabilistic)
Free tier (April 2026) 10K assessments/month 10K assessments/month
Keys interchangeable? No — v2 and v3 keys are separate

reCAPTCHA v2: The Blunt Instrument

v2 presents users with a checkbox ("I'm not a robot") and escalates to image challenges when Google's risk analysis is uncertain. Users either solve the challenge or they don't — your server gets a simple pass/fail.

PHP Implementation

<!-- v2 checkbox widget -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

<form method="POST" action="/submit.php">
  <input type="email" name="email" required>
  <div class="g-recaptcha" data-sitekey="YOUR_V2_SITE_KEY"></div>
  <button type="submit">Send</button>
</form>
<?php
// reCAPTCHA v2 verification — binary result
function verifyRecaptchaV2(string $token, string $secret): bool
{
    $ch = curl_init('https://www.google.com/recaptcha/api/siteverify');
    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,
    ]);

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

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

$valid = verifyRecaptchaV2(
    $_POST['g-recaptcha-response'] ?? '',
    getenv('RECAPTCHA_V2_SECRET') ?: '',
);

v2's strength: Simplicity. You don't need to choose thresholds, monitor score distributions, or build fallback logic. It either passes or it doesn't.

v2's weakness: UX friction. Image challenges take 10+ seconds to solve. CAPTCHAs reduce form completions by up to 40%. And AI now solves v2's image challenges with near-perfect accuracy (ETH Zurich demonstrated 100% on reCAPTCHA v2 using YOLOv8) — so the friction hurts users more than bots.

reCAPTCHA v3: The Score You Have to Manage

v3 runs invisibly in the background, analyzing user behavior (mouse movements, browsing patterns, cookies) and returning a score between 0.0 and 1.0. You decide what to do with that score.

PHP Implementation

<!-- v3 — runs on every page load, not just forms -->
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_V3_SITE_KEY"></script>

<form method="POST" action="/submit.php" id="contactForm">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <input type="hidden" name="recaptcha_token" id="recaptchaToken">
  <button type="submit">Send</button>
</form>

<script>
document.getElementById('contactForm').addEventListener('submit', function(e) {
  e.preventDefault();
  grecaptcha.ready(function() {
    // Use a unique action name per form — critical for accurate scoring
    grecaptcha.execute('YOUR_V3_SITE_KEY', {action: 'contact_submit'})
      .then(function(token) {
        document.getElementById('recaptchaToken').value = token;
        document.getElementById('contactForm').submit();
      });
  });
});
</script>
<?php
// reCAPTCHA v3 verification — returns score, you decide the threshold
function verifyRecaptchaV3(string $token, string $secret, string $expectedAction): array
{
    $ch = curl_init('https://www.google.com/recaptcha/api/siteverify');
    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);
    curl_close($ch);

    $data = json_decode($response ?: '{}', true);

    return [
        'success' => ($data['success'] ?? false)
                     && ($data['action'] ?? '') === $expectedAction,
        'score'   => $data['score'] ?? 0.0,
    ];
}

$result = verifyRecaptchaV3(
    token: $_POST['recaptcha_token'] ?? '',
    secret: getenv('RECAPTCHA_V3_SECRET') ?: '',
    expectedAction: 'contact_submit',
);

if (!$result['success']) {
    $errors[] = 'Verification failed.';
} elseif ($result['score'] < 0.5) {
    // Low score — escalate (show v2 challenge, require email verification, etc.)
    $errors[] = 'Additional verification required.';
}

v3 Score Management: The Hidden Complexity

New sites get unreliable scores. When you first deploy v3, Google has no behavioral data for your site. Scores may be 0.9 for everyone — bots and humans alike — during the "learning period" (up to 7 days). Don't trust scores until you have at least a week of traffic data.

VPN and Tor users score low. Privacy-conscious users are widely reported to score 0.1–0.3 (community-documented, not confirmed by Google) because Google can't track their browsing history. A 0.5 threshold silently blocks these users with no explanation and no recourse.

Score distributions shift. A threshold that works today may block legitimate users next month as Google updates its models. You need ongoing monitoring.

The action parameter matters. Most tutorials use action: 'submit' for everything. In production, each form should have a unique action name (login, register, contact). Without action separation, Google can't learn your traffic patterns, and scores stay inaccurate.

Tokens expire in 2 minutes. Users filling out long forms with many fields — or users with disabilities who need more time — will submit expired tokens. Build refresh logic or accept that some legitimate submissions will fail.

No explanation for low scores. Google only provides reason codes in the Enterprise tier. On the free/standard tier, a user scores 0.2 and you have no idea why. You can't debug it, tune it, or explain it to the user.

Taken together, v3 is less a plug-in CAPTCHA and more an ongoing risk-scoring system you have to operate. If that operational burden sounds excessive for a contact form, it probably is.

The Hybrid Approach (v2 + v3)

The production-ready pattern most articles miss: use v3 for everyone, fall back to v2 for ambiguous scores.

<?php
// Hybrid v2+v3: invisible for most users, challenge for edge cases
$result = verifyRecaptchaV3(
    token: $_POST['recaptcha_token'] ?? '',
    secret: getenv('RECAPTCHA_V3_SECRET') ?: '',
    expectedAction: 'contact_submit',
);

if (!$result['success']) {
    $errors[] = 'Verification failed.';
} elseif ($result['score'] >= 0.7) {
    // High confidence human — proceed
} elseif ($result['score'] >= 0.3) {
    // Ambiguous — show v2 challenge
    $_SESSION['needs_v2_challenge'] = true;
    // Redirect back to form with v2 widget visible
} else {
    // Almost certainly a bot — reject
    $errors[] = 'Submission blocked.';
}

In your form template, conditionally load the v2 widget:

<?php if (!empty($_SESSION['needs_v2_challenge'])): ?>
  <script src="https://www.google.com/recaptcha/api.js" async defer></script>
  <div class="g-recaptcha" data-sitekey="YOUR_V2_SITE_KEY"></div>
<?php endif; ?>

This gives you v3's invisible UX for most users and v2's hard verification for edge cases. The downside: you're now managing two sets of keys, two verification flows, and the score threshold that triggers escalation.

The April 2026 Pricing Reality

Both v2 and v3 now share the same pricing:

Tier Assessments/Month Cost
Free Up to 10,000 $0
Standard 10,001–100,000 $8/month
Enterprise 100,001+ Custom pricing

The hidden cost of v3: Google recommends running v3 on every page load, not just form submissions, to improve scoring accuracy. Every page view counts as an assessment. A site with 1,000 daily visitors browsing 3 pages each burns through 90,000 assessments/month — well past the free tier.

The legal shift: As of April 2, 2026, Google moved from data controller to data processor for reCAPTCHA. You, the site operator, are now the GDPR data controller. You're responsible for lawful basis, consent, and data subject requests. Update your privacy policy accordingly. See our reCAPTCHA PHP docs for the updated compliance requirements.

When v2 Still Makes Sense

When v3 Makes Sense

When to Skip Both

If you're choosing a CAPTCHA for a new project in 2026, you have better options than either version of reCAPTCHA.

Verdict

v2 is simpler but adds friction. v3 removes friction but adds complexity. Both now charge after 10K assessments/month, and both send user data to Google's US servers.

If you're already running reCAPTCHA and it's working, the hybrid v2+v3 approach is the most robust setup. If you're starting fresh or the pricing change is forcing a decision, Turnstile is the pragmatic choice — same invisible UX as v3, none of the score management headache, and a free tier that won't run out.

The real question isn't v2 vs v3 — it's whether reCAPTCHA's shrinking free tier and growing operational burden are worth it when invisible, free alternatives exist.