Cloudflare Turnstile is a verification tool, much like CAPTCHA. It was added to the sign up form 12 December 2025.

Overview

  1. We use managed mode with proper race condition handling. The widget runs verification in the background, only showing a challenge UI when Cloudflare determines it’s necessary (managed mode).
  2. Server-side validation: We validate Turnstile tokens server-side with Cloudflare’s API before calling Supabase. This provides granular control (CAPTCHA only on sign-up, not also sign-in and password reset as Supabase requires) while maintaining security.

To reiterate: we no longer use Supabase’s built-in CAPTCHA feature because it’s so wide-sweeping. All validation happens in our server action before calling Supabase.

Implementation details

We use Turnstile’s managed variant, which:

  1. Runs invisibly by default: Most legitimate users never see a CAPTCHA challenge.
  2. Shows challenges when needed: Cloudflare automatically displays a challenge if it detects suspicious behaviour (managed mode).
  3. Handles race conditions: The form waits for token generation before submission, preventing premature form submits.
  4. Provides clear feedback: Users see "Verifying..." state while waiting, and error messages if verification fails.

Security model

Why this is secure even though Supabase doesn't know about the CAPTCHA:

  1. Server-side validation gate: The signUpAction validates the Turnstile token with Cloudflare's API before calling Supabase.
  2. No token means no sign-up: If validation fails, the function returns early and Supabase is never called.
  3. Secret key validation: The server uses TURNSTILE_SECRET_KEY (never exposed to clients) to verify tokens with Cloudflare.
  4. Bots can’t bypass: Even if a bot bypasses the frontend, they can’t produce a valid token without solving the challenge.

Environment variables

Turnstile verification requires three environment variables:

  1. NEXT_PUBLIC_TURNSTILE_SITEKEY: Cloudflare Turnstile site key (public, used client-side)