Cloudflare Turnstile

Clouflare Turnstile is a friendly, free CAPTCHA replacement, and it works seamlessly with Supabase Edge Functions to protect your forms. View on GitHub.



Create a new function in your project:

1supabase functions new cloudflare-turnstile

And add the code to the index.ts file:

import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
import { corsHeaders } from '../_shared/cors.ts'

console.log('Hello from Cloudflare Trunstile!')

function ips(req: Request) {
  return req.headers.get('x-forwarded-for')?.split(/\s*,\s*/)

serve(async (req) => {
  // This is needed if you're planning to invoke your function from a browser.
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })

  const { token } = await req.json()
  const clientIps = ips(req) || ['']
  const ip = clientIps[0]

  // Validate the token by calling the
  // "/siteverify" API endpoint.
  let formData = new FormData()
  formData.append('secret', Deno.env.get('CLOUDFLARE_SECRET_KEY') ?? '')
  formData.append('response', token)
  formData.append('remoteip', ip)

  const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
  const result = await fetch(url, {
    body: formData,
    method: 'POST',

  const outcome = await result.json()
  if (outcome.success) {
    return new Response('success', { headers: corsHeaders })
  return new Response('failure', { headers: corsHeaders })

Deploy the server-side validation Edge Functions#

1supabase functions deploy cloudflare-turnstile
2supabase secrets set CLOUDFLARE_TURNSTILE_SECRET_KEY=your_secret_key

Invoke the function from your site#

const { data, error } = await supabase.functions.invoke('cloudflare-turnstile', {
  body: { token },
Need some help?

Not to worry, our specialist engineers are here to help. Submit a support ticket through the Dashboard.