Ama

Solo Dev

Adding Cloudflare Turnstile to Next.js App (Free Plan)

Cloudflare Turnstile is a CAPTCHA alternative that's privacy-first, user-friendly, and completely free. Unlike traditional CAPTCHAs, Turnstile doesn't ask users to click on buses or traffic lights—it runs silently in the background and protects your forms with a simple token verification.

In this post, we'll add Turnstile to a basic contact form in a Next.js 14 App Router project using the free Cloudflare plan.

✅ Step 1: Sign Up and Get Site Key

  1. Go to dash.cloudflare.com/turnstile
  2. Add a new site
    • Site name: e.g. myapp.com
    • Widget type: "Managed" (recommended)
    • Domain: Add your domain or use localhost for testing
  3. Copy the Site Key and Secret Key

🛠️ Step 2: Install Turnstile in Your Form

npm install react-turnstile

Create your form component, e.g. app/contact/page.tsx:

'use client';
import React, { useState } from 'react';
import Turnstile from 'react-turnstile';

export default function ContactForm() {
  const [token, setToken] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const res = await fetch('/api/verify-turnstile', {
      method: 'POST',
      body: JSON.stringify({ token }),
    });

    const data = await res.json();
    if (data.success) {
      alert('Verified!');
    } else {
      alert('Verification failed');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />
      <Turnstile
        sitekey="YOUR_SITE_KEY"
        onVerify={(token) => setToken(token)}
      />
      <button type="submit">Send</button>
    </form>
  );
}

🔒 Step 3: Backend Verification (API Route)

Create app/api/verify-turnstile/route.ts:

import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const { token } = await request.json();

  const secret = process.env.TURNSTILE_SECRET_KEY;
  const res = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: `secret=${secret}&response=${token}`,
  });

  const data = await res.json();
  return NextResponse.json(data);
}

Don't forget to set TURNSTILE_SECRET_KEY in your .env.local:

TURNSTILE_SECRET_KEY=your_secret_key_here

🧪 Test It!

  1. Run your app: npm run dev
  2. Fill the form and submit
  3. You'll get a verified or failed message depending on the response

🧠 Final Tips

  • Turnstile works with any plan, including free
  • You can integrate it into login, signup, comments, or any form
  • No need for user interaction = better UX than reCAPTCHA

Why Choose Turnstile?

  • Privacy-focused: No tracking or personal data collection
  • User-friendly: Often invisible to legitimate users
  • Free: No cost for basic usage
  • Easy integration: Simple API with good documentation
  • Reliable: Powered by Cloudflare's global network

Turnstile is an excellent choice for protecting your forms while maintaining a great user experience. The free plan is perfect for most small to medium applications, and the setup process is straightforward with Next.js.

We use cookies

We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.