Scripts

Google reCAPTCHA

Google reCAPTCHA protects your site from spam and abuse using advanced risk analysis.

Nuxt Scripts provides a registry script composable useScriptGoogleRecaptcha() to easily integrate reCAPTCHA v3 in your Nuxt app.

This integration supports reCAPTCHA v3 (score-based, invisible) only. For v2 checkbox, use the standard reCAPTCHA integration.
Google reCAPTCHA

View source

Nuxt Config Setup

The simplest way to load Google reCAPTCHA globally in your Nuxt App is to use Nuxt config. Alternatively you can directly use the useScriptGoogleRecaptcha composable.

export default defineNuxtConfig({
  scripts: {
    registry: {
      googleRecaptcha: {
        siteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
      }
    }
  }
})

useScriptGoogleRecaptcha()

The useScriptGoogleRecaptcha composable lets you have fine-grain control over when and how Google reCAPTCHA is loaded on your site.

const { proxy } = useScriptGoogleRecaptcha()

const token = await proxy.grecaptcha.execute(siteKey, { action: 'submit' })

Please follow the Registry Scripts guide to learn more about advanced usage.

Enterprise

For reCAPTCHA Enterprise, set the enterprise option to true:

export default defineNuxtConfig({
  scripts: {
    registry: {
      googleRecaptcha: {
        siteKey: 'YOUR_SITE_KEY',
        enterprise: true
      }
    }
  }
})

China Support

For sites that need to work in China, use recaptchaNet: true to load from recaptcha.net instead of google.com:

export default defineNuxtConfig({
  scripts: {
    registry: {
      googleRecaptcha: {
        siteKey: 'YOUR_SITE_KEY',
        recaptchaNet: true
      }
    }
  }
})

Server-Side Verification

reCAPTCHA tokens must be verified on your server. Create an API endpoint to validate the token:

export default defineEventHandler(async (event) => {
  const { token } = await readBody(event)
  const secretKey = process.env.RECAPTCHA_SECRET_KEY

  const response = await $fetch('https://www.google.com/recaptcha/api/siteverify', {
    method: 'POST',
    body: new URLSearchParams({
      secret: secretKey,
      response: token,
    }),
  })

  if (!response.success || response.score < 0.5) {
    throw createError({
      statusCode: 400,
      message: 'reCAPTCHA verification failed',
    })
  }

  return { success: true, score: response.score }
})
Never expose your secret key on the client. Always verify tokens server-side.

Hiding the Badge

reCAPTCHA v3 displays a badge in the corner of your site. You can hide it with CSS, but you must include attribution in your form:

.grecaptcha-badge { visibility: hidden; }
<p>This site is protected by reCAPTCHA and the Google
  <a href="https://policies.google.com/privacy">Privacy Policy</a> and
  <a href="https://policies.google.com/terms">Terms of Service</a> apply.
</p>

Test Keys

Google provides test keys for development that always pass verification. Use these for local testing:

Key TypeValue
Site Key6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
Secret Key6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
Test keys will always return success: true with a score of 0.9. See Google's FAQ for more details.
nuxt.config.ts
export default defineNuxtConfig({
  $development: {
    scripts: {
      registry: {
        googleRecaptcha: {
          siteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
        }
      }
    }
  }
})
siteKeystring required

Your reCAPTCHA site key.

enterpriseboolean

Use the Enterprise version of reCAPTCHA (enterprise.js instead of api.js).

recaptchaNetboolean

Use recaptcha.net instead of google.com domain. Useful for regions where google.com is blocked.

hlstring

Language code for the reCAPTCHA widget.

Example

Using reCAPTCHA v3 to protect a form submission with server-side verification.

<script setup lang="ts">
const { onLoaded } = useScriptGoogleRecaptcha()

const name = ref('')
const email = ref('')
const message = ref('')
const status = ref<'idle' | 'loading' | 'success' | 'error'>('idle')

async function onSubmit() {
  status.value = 'loading'

  onLoaded(async ({ grecaptcha }) => {
    // Get reCAPTCHA token
    const token = await grecaptcha.execute('YOUR_SITE_KEY', { action: 'contact' })

    // Send form data + token to your API for verification
    const result = await $fetch('/api/contact', {
      method: 'POST',
      body: {
        token,
        name: name.value,
        email: email.value,
        message: message.value
      }
    }).catch(() => null)

    status.value = result ? 'success' : 'error'
  })
}
</script>

<template>
  <form @submit.prevent="onSubmit">
    <input v-model="name" placeholder="Name" required>
    <input v-model="email" type="email" placeholder="Email" required>
    <textarea v-model="message" placeholder="Message" required />
    <button type="submit" :disabled="status === 'loading'">
      {{ status === 'loading' ? 'Sending...' : 'Submit' }}
    </button>
    <p v-if="status === 'success'">
      Message sent!
    </p>
    <p v-if="status === 'error'">
      Failed to send. Please try again.
    </p>
  </form>
</template>