---
title: "Google reCAPTCHA"
description: "Use Google reCAPTCHA v3 in your Nuxt app."
canonical_url: "https://scripts.nuxt.com/scripts/google-recaptcha"
last_updated: "2026-05-03T02:50:07.399Z"
---

[Google reCAPTCHA](https://www.google.com/recaptcha/about/) protects your site from spam and abuse using advanced risk analysis.

Nuxt Scripts provides a registry script composable [`useScriptGoogleRecaptcha()`](/scripts/google-recaptcha) to easily integrate reCAPTCHA v3 in your Nuxt app.

<callout>

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

</callout>

<script-stats>



</script-stats>

<script-docs :sections="["setup", "composable"]">



</script-docs>

## Enterprise

For reCAPTCHA Enterprise, set the `enterprise` option to `true`:

```ts
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`:

```ts
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:

<code-group>

```ts [server/api/verify-recaptcha.post.ts]
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 }
})
```

```ts [Enterprise - server/api/verify-recaptcha.post.ts]
export default defineEventHandler(async (event) => {
  const { token } = await readBody(event)
  const projectId = process.env.RECAPTCHA_PROJECT_ID
  const apiKey = process.env.RECAPTCHA_API_KEY
  const siteKey = process.env.NUXT_PUBLIC_SCRIPTS_GOOGLE_RECAPTCHA_SITE_KEY

  const response = await $fetch(
    `https://recaptchaenterprise.googleapis.com/v1/projects/${projectId}/assessments?key=${apiKey}`,
    {
      method: 'POST',
      body: {
        event: { token, siteKey, expectedAction: 'submit' },
      },
    }
  )

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

  return { success: true, score: response.riskAnalysis.score }
})
```

</code-group>

<callout type="warning">

Never expose your secret key on the client. Always verify tokens server-side.

</callout>

## 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:

```css
.grecaptcha-badge { visibility: hidden; }
```

```html
<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:

<table>
<thead>
  <tr>
    <th>
      Key Type
    </th>
    
    <th>
      Value
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Site Key
    </td>
    
    <td>
      <code>
        6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Secret Key
    </td>
    
    <td>
      <code>
        6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
      </code>
    </td>
  </tr>
</tbody>
</table>

<callout type="info">

Test keys will always return `success: true` with a score of `0.9`. See [Google's FAQ](https://developers.google.com/recaptcha/docs/faq#id-like-to-run-automated-tests-with-recaptcha.-what-should-i-do) for more details.

</callout>

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  $development: {
    scripts: {
      registry: {
        googleRecaptcha: {
          siteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
        }
      }
    }
  }
})
```

<script-types>



</script-types>

## Example

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

<code-group>

```vue [ContactForm.vue]
<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>
```

```ts [server/api/contact.post.ts]
export default defineEventHandler(async (event) => {
  const { token, name, email, message } = await readBody(event)

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

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

  // Process the contact form (send email, save to DB, etc.)
  console.log('Contact form submitted:', { name, email, message, score: verification.score })

  return { success: true }
})
```

</code-group>
