Vue Cloudflare Turnstile Component
vue-turnstile is a Vue 3 component library that simplifies the integration of Cloudflare Turnstile, a CAPTCHA alternative, into Vue applications. It provides a declarative `VueTurnstile` component that handles the underlying Turnstile API interactions, script loading, and token management. The current stable version is 1.0.11, suggesting a mature library actively maintained for Vue 3 environments. While a specific release cadence isn't published, the `1.0.x` versioning implies ongoing maintenance and minor updates as needed. Key differentiators include its tight integration with Vue's reactivity system (e.g., `v-model` for token binding), support for various Turnstile customization options like theme, size, and language, and explicit methods for resetting and re-rendering the widget. It abstracts away the complexities of directly interacting with the Cloudflare Turnstile JavaScript API, making it easier for developers to implement bot protection.
Common errors
-
[vue-turnstile] site-key is required
cause The `site-key` prop was not provided to the `VueTurnstile` component.fix<vue-turnstile site-key="YOUR_SITE_KEY" v-model="token" /> -
Refused to load the script 'https://challenges.cloudflare.com/turnstile/v0/api.js' because it violates the following Content Security Policy directive...
cause Your browser's Content Security Policy (CSP) is blocking the necessary Cloudflare Turnstile scripts from loading.fixModify your Content Security Policy (CSP) to permit scripts and frames from `https://challenges.cloudflare.com`. For example, add `script-src https://challenges.cloudflare.com; frame-src https://challenges.cloudflare.com;` to your CSP headers or meta tag. -
Error in beforeUpdate: 'TypeError: Cannot read properties of undefined (reading 'reset')'
cause Attempting to call a component method (like `reset()`) on a `VueTurnstile` instance that hasn't been properly assigned a ref or is not yet mounted.fixEnsure you have a `ref` attribute on the `VueTurnstile` component (e.g., `<vue-turnstile ref="turnstileWidget" ... />`) and access its methods using `this.$refs.turnstileWidget.reset()` after the component is mounted. Use optional chaining for robustness: `(this.$refs.turnstileWidget as any)?.reset()`.
Warnings
- gotcha Cloudflare Turnstile tokens are valid only for a limited time (typically 5 minutes). Ensure your backend validates the token promptly upon submission. If the user delays, the token might expire. The `reset-interval` prop can automatically refresh the token client-side.
- gotcha The `site-key` prop is mandatory. Using the placeholder `1x00000000000000000000AA` (which is a test key) is fine for development, but for production, you must use a valid site key obtained from your Cloudflare account.
- gotcha Cloudflare Turnstile relies on loading scripts and resources from `challenges.cloudflare.com`. If your application uses a Content Security Policy (CSP), you must configure it to allow these resources, otherwise the widget will fail to render.
Install
-
npm install vue-turnstile -
yarn add vue-turnstile -
pnpm add vue-turnstile
Imports
- VueTurnstile
const VueTurnstile = require('vue-turnstile');import VueTurnstile from 'vue-turnstile';
- VueTurnstile component type (for TypeScript)
import type { VueTurnstile } from 'vue-turnstile';
Quickstart
<script lang="ts">
import VueTurnstile from 'vue-turnstile';
export default {
components: { VueTurnstile },
data() {
return {
token: '',
};
},
methods: {
// Example of how to access component methods via ref
resetTurnstile() {
(this.$refs.turnstileWidget as typeof VueTurnstile & { reset: () => void } | undefined)?.reset();
}
}
};
</script>
<template>
<div>
<p>Please complete the CAPTCHA:</p>
<vue-turnstile
site-key="1x00000000000000000000AA" <!-- Replace with your actual site key -->
v-model="token"
theme="auto"
size="normal"
language="en"
ref="turnstileWidget"
/>
<div v-if="token">
<p>Turnstile Token: <code>{{ token }}</code></p>
<button @click="resetTurnstile">Reset Turnstile</button>
</div>
<div v-else>
<p>Awaiting Turnstile token...</p>
</div>
</div>
</template>
<style>
/* Basic styling for demonstration */
div {
font-family: Arial, sans-serif;
margin-bottom: 10px;
}
button {
padding: 8px 15px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>