Skip to content

Using Cloudflare Turnstile on a Astro form

Here’s how I used Cloudflare Turnstile on a Astro form to prevent spam and form submission abuse.

Set Turnstile up in the Cloudflare panel first, and grab the TURNSTILE_SITE_KEY and TURNSTILE_SITE_SECRET variables, put them in .env or anywhere you manage env vars.

Then in the Astro component:

<script
    is:inline
    src='https://challenges.cloudflare.com/turnstile/v0/api.js'
    defer
    async></script>

<form method='post'>
 ...
	<div
	  class='cf-turnstile'
	  data-sitekey={import.meta.env
	    .TURNSTILE_SITE_KEY ||
	    process.env.TURNSTILE_SITE_KEY}>
	</div>

  <input
    type='submit'
    value='Login'
  />
</form>

On the server endpoint (might be same page, or not):

export async function processTurnstile(
  cf_turnstile_response: string
) {
  const url =
    'https://challenges.cloudflare.com/turnstile/v0/siteverify'

  const requestBody = new URLSearchParams({
    secret:
      import.meta.env.TURNSTILE_SITE_SECRET ||
      process.env.TURNSTILE_SITE_SECRET,
    response: cf_turnstile_response
  })

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: requestBody.toString()
  })

  const data = await response.json()

  return data.success
}

if (Astro.request.method === 'POST') {
  const formData = await Astro.request.formData()

  const email = formData.get('email')?.toString() || ''
  const password =
    formData.get('password')?.toString() || ''

	const is_valid_turnstile = await processTurnstile(
    formData.get('cf-turnstile-response')?.toString() || ''
  )

  if (!is_valid_turnstile) {
    console.log('Invalid turnstile')
  } else {
		//valid, do something
  }
}

→ Here's my latest YouTube video

→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter

JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025

Bootcamp 2025

Join the waiting list