Skip to content

Captcha

Verifies an x-captcha-response header against a CAPTCHA provider before the protected endpoints run. Supports Cloudflare Turnstile, Google reCAPTCHA, hCaptcha and CaptchaFox. Mirrors the TS captcha() plugin.

Enable

python
from better_auth import BetterAuth
from better_auth.plugins_ext import CaptchaPlugin

auth = BetterAuth(
    secret="a-strong-32-character-minimum-secret",
    plugins=[
        CaptchaPlugin(provider="cloudflare-turnstile", secret_key="your-secret-key")
    ],
)

Options

OptionTypeDefaultDescription
providerstrrequired"cloudflare-turnstile", "google-recaptcha", "hcaptcha" or "captchafox".
secret_keystrrequiredThe provider's siteverify secret.
endpointslist[str] | NoneNone (["/sign-up/email", "/sign-in/email", "/request-password-reset"])Paths to protect. /sign-in/email-otp is exempt unless named explicitly.
site_verify_url_overridestr | NoneNoneAlternate siteverify endpoint.
min_scorefloat0.5Minimum score (score-based providers, e.g. reCAPTCHA v3).
expected_actionstr | NoneNoneExpected action claim.
allowed_hostnameslist[str] | NoneNoneAccepted hostnames in the provider response.
site_keystr | NoneNoneSite key (providers that verify it server-side).

Endpoints

None added — the plugin runs in on_request, after core rate limiting and before route dispatch, so a rejected captcha never reaches the endpoint handler.

Notes

  • Fails closed: any non-2xx, transport error or malformed body from the provider's siteverify endpoint is a 500, never a pass.
  • Flattened option set: only the fields relevant to the configured provider are read (the TS options are a per-provider union).

MIT licensed · API-compatible with better-auth