JSPM

nuxt4-turnstile

1.0.4
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 50
  • Score
    100M100P100Q80037F
  • License MIT

Cloudflare Turnstile integration for Nuxt 4 - A privacy-focused CAPTCHA alternative

Package Exports

  • nuxt4-turnstile

Readme

Nuxt4 Turnstile

npm version Nuxt License: MIT

Cloudflare Turnstile integration for Nuxt 4 - A privacy-focused CAPTCHA alternative.

Nuxt4 Turnstile Demo

โœจ Features

  • ๐Ÿ”’ Privacy-focused - No tracking, no cookies, no fingerprinting
  • ๐Ÿš€ Nuxt 4 Compatible - Built specifically for Nuxt 4
  • ๐Ÿ“ฆ Auto-imported - Components and composables ready to use
  • ๐Ÿ›ก๏ธ Server Validation - Built-in server-side token verification
  • ๐ŸŽจ Customizable - Theme, size, appearance options
  • โ™ป๏ธ Auto-refresh - Automatically refreshes tokens before expiry
  • ๐Ÿ“ TypeScript - Full TypeScript support

๐Ÿ“ฆ Installation

# npm
npm install nuxt4-turnstile

# pnpm
pnpm add nuxt4-turnstile

# bun
bun add nuxt4-turnstile

โš™๏ธ Configuration

Add nuxt4-turnstile to your nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['nuxt4-turnstile'],

  turnstile: {
    siteKey: 'your-site-key', // Get from Cloudflare Dashboard
  },

  runtimeConfig: {
    turnstile: {
      // Override with NUXT_TURNSTILE_SECRET_KEY env variable
      secretKey: '',
    },
  },
})

Get Your Keys

  1. Go to Cloudflare Turnstile
  2. Create a new site
  3. Copy your Site Key (public) and Secret Key (server-side)

Configuration Options

Option Type Default Description
siteKey string '' Your Turnstile site key (required)
secretKey string '' Your Turnstile secret key (server-side)
addValidateEndpoint boolean false Add /_turnstile/validate endpoint
appearance 'always' | 'execute' | 'interaction-only' 'always' Widget visibility
theme 'light' | 'dark' | 'auto' 'auto' Widget theme
size 'normal' | 'compact' | 'flexible' 'normal' Widget size
retry 'auto' | 'never' 'auto' Retry behavior
retryInterval number 8000 Retry interval in ms
refreshExpired number 250 Auto-refresh before expiry (seconds)
language string 'auto' Widget language

๐Ÿš€ Usage

Component

Use the auto-imported <NuxtTurnstile> component:

<template>
  <form @submit.prevent="onSubmit">
    <NuxtTurnstile v-model="token" />
    <button type="submit" :disabled="!token">Submit</button>
  </form>
</template>

<script setup>
const token = ref('')

async function onSubmit() {
  // Send token to your server for verification
  await $fetch('/api/contact', {
    method: 'POST',
    body: { token, message: '...' }
  })
}
</script>

[!TIP] If you are using a form component that restricts content (like Nuxt UI Pro's <AuthForm>), make sure to place <NuxtTurnstile> in a supported slot (e.g., #validation or #footer) instead of the default slot.

Component Props

Prop Type Description
v-model string Two-way binding for the token
element string HTML element to use (default: 'div')
options TurnstileOptions Override module options
action string Custom action for analytics
cData string Custom data payload

Component Events

Event Payload Description
@verify token: string Token generated
@expire - Token expired
@error error: Error Error occurred
@before-interactive - Before challenge
@after-interactive - After challenge
@unsupported - Browser unsupported

Component Methods (via ref)

<template>
  <NuxtTurnstile ref="turnstile" v-model="token" />
  <button @click="turnstile?.reset()">Reset</button>
</template>

<script setup>
const turnstile = ref()
const token = ref('')
</script>
Method Description
reset() Reset widget for re-verification
remove() Remove widget from DOM
getResponse() Get current token
isExpired() Check if token is expired
execute() Execute invisible challenge

๐Ÿ›ก๏ธ Server Verification

Using the Built-in Endpoint

Enable the validation endpoint in your config:

export default defineNuxtConfig({
  turnstile: {
    siteKey: '...',
    addValidateEndpoint: true,
  },
})

Then call it from your client:

const { success } = await $fetch('/_turnstile/validate', {
  method: 'POST',
  body: { token }
})

Using the Helper Function

In your server routes:

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

  // Verify the token
  const result = await verifyTurnstileToken(token)

  if (!result.success) {
    throw createError({
      statusCode: 400,
      message: 'Invalid captcha'
    })
  }

  // Continue with your logic...
  return { success: true }
})

Verification Options

await verifyTurnstileToken(token, {
  secretKey: 'override-secret',  // Override config secret
  remoteip: '1.2.3.4',           // Client IP for security
  action: 'login',               // Validate expected action
  cdata: 'user-123',             // Validate expected cdata
})

๐Ÿ”ง Composable

Use the useTurnstile composable for programmatic access:

const {
  isAvailable,  // Is Turnstile loaded?
  siteKey,      // Get site key
  verify,       // Verify token via endpoint
  render,       // Render widget programmatically
  reset,        // Reset widget
  remove,       // Remove widget
  getResponse,  // Get token
  isExpired,    // Check expiry
  execute,      // Execute invisible challenge
} = useTurnstile()

๐ŸŒ Environment Variables

Override configuration with environment variables:

NUXT_PUBLIC_TURNSTILE_SITE_KEY=your-site-key
NUXT_TURNSTILE_SECRET_KEY=your-secret-key

๐Ÿ“ TypeScript

Types are automatically available:

import type {
  TurnstileInstance,
  TurnstileOptions,
  TurnstileVerifyResponse,
} from 'nuxt4-turnstile'

๐Ÿงช Testing

For testing, use Cloudflare's test keys:

Key Behavior
1x00000000000000000000AA Always passes
2x00000000000000000000AB Always blocks
3x00000000000000000000FF Forces interactive challenge

Secret test keys:

Key Behavior
1x0000000000000000000000000000000AA Always passes
2x0000000000000000000000000000000AA Always fails
3x0000000000000000000000000000000AA Yields token spend error

๐Ÿ“„ License

MIT License - see LICENSE for details.