Skip to content
FLAVIO COPES
flaviocopes.com
2026

Using reCAPTCHA on a Astro form

By Flavio Copes

Learn how to add Google reCAPTCHA to an Astro form to stop spam, wiring the widget with your site key and verifying the response on the server with siteverify.

~~~

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

Set Recaptcha first, and grab the RECAPTCHA_SITE_KEY and RECAPTCHA_SECRET_KEY variables, put them in .env or anywhere you manage env vars.

Then in the Astro component:

<script
  is:inline
  src='https://www.google.com/recaptcha/api.js'></script>
<script is:inline>
  function recaptcha() {
    document.querySelector('form').submit()
  }
</script>

<form method='post'>
 ...
  <input
    type='submit'
    class='block w-full px-3 py-2 mt-8 text-sm font-semibold text-center text-white cursor-pointer leading-6 rounded-md g-recaptcha focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 ring-1 ring-inset ring-blue-200 hover:ring-blue-300 hover:bg-blue-600'
    data-sitekey={import.meta.env
      .RECAPTCHA_SITE_KEY ||
      process.env.RECAPTCHA_SITE_KEY}
    data-callback='recaptcha'
    data-action='submit'
    value='Login'
  />
</form>

Server-side form POST request handler:

export async function processCaptcha(g_recaptcha_response: string) {
  const url =
    'https://www.google.com/recaptcha/api/siteverify'

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

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

  const data = await response.json()

  console.log(data)
  /*
  {
    success: true,
    challenge_ts: '2024-01-20T18:18:12Z',
    hostname: 'localhost',
    score: 0.9,
    action: 'submit'
  }
  */

  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 g_recaptcha_response =
    formData.get('g-recaptcha-response')?.toString() || ''

  const is_valid_captcha = await processCaptcha(g_recaptcha_response)

  if (!is_valid_captcha) {
    error = 'Invalid captcha'
  } else {
		//valid
  }
}
Tagged: Astro · All topics
~~~

Related posts about astro: