next-turnstile
Version:
Cloudflare Turnstile integration for Next.js applications
235 lines (181 loc) โข 7.02 kB
Markdown
# Next-Turnstile
A type-safe, feature-rich integration of Cloudflare Turnstile for Next.js applications. This package provides both client and server-side components for seamless CAPTCHA integration.
[](https://www.npmjs.com/package/next-turnstile)
[](https://opensource.org/licenses/MIT)
## Features
- ๐ **Type-safe**: Full TypeScript support
- ๐จ **Customizable**: Extensive styling and behavior options
- ๐งช **Sandbox Mode**: Built-in support for development testing
- โก **Server Validation**: Easy token verification
- ๐ฑ **Responsive**: Works across all device sizes
- ๐ **Auto-reload**: Configurable token refresh
- ๐ **Theme Support**: Light, dark, and auto themes
- ๐ **i18n Ready**: Multiple language support
## Installation
```bash
# npm
npm install next-turnstile
# yarn
yarn add next-turnstile
# pnpm
pnpm add next-turnstile
# bun
bun add next-turnstile
```
## Quick Start
### Client-Side Usage
```tsx
import { Turnstile } from "next-turnstile";
function MyForm() {
const handleVerify = (token: string) => {
// Handle the verification token
console.log("Verification successful:", token);
};
return (
<Turnstile siteKey="your-site-key" onVerify={handleVerify} theme="light" />
);
}
```
### Server-Side Validation
```tsx
import { validateTurnstileToken } from "next-turnstile";
async function validateToken(token: string) {
try {
const result = await validateTurnstileToken({
token,
secretKey: process.env.TURNSTILE_SECRET_KEY,
});
if (result.success) {
// Token is valid
return true;
}
} catch (error) {
console.error("Validation failed:", error);
}
return false;
}
```
## API Reference
### Turnstile Component Props
| Prop | Type | Default | Description |
| ---------------- | --------------------------------------------- | -------------------- | ----------------------------------- |
| `siteKey` | `string` | Required | Your Cloudflare Turnstile site key |
| `onVerify` | `(token: string) => void` | - | Callback when verification succeeds |
| `onError` | `(error: unknown) => void` | - | Callback when an error occurs |
| `onExpire` | `() => void` | - | Callback when the token expires |
| `onLoad` | `() => void` | - | Callback when the widget loads |
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Widget theme |
| `size` | `'normal' \| 'compact'` | `'normal'` | Widget size |
| `appearance` | `'always' \| 'execute' \| 'interaction-only'` | `'always'` | When to show the widget |
| `retry` | `'auto' \| 'never'` | `'auto'` | Retry behavior on failure |
| `retryInterval` | `number` | `8000` | Milliseconds between retries |
| `refreshExpired` | `'auto' \| 'manual' \| 'never'` | `'auto'` | Token refresh behavior |
| `language` | `string` | - | Widget language code |
| `id` | `string` | `'turnstile-widget'` | Container element ID |
| `className` | `string` | - | Additional CSS classes |
| `sandbox` | `boolean` | `false` | Enable sandbox mode |
### Server Validation Options
| Option | Type | Required | Description |
| ---------------- | --------- | -------- | ------------------------- |
| `token` | `string` | Yes | The token from the client |
| `secretKey` | `string` | Yes | Your Turnstile secret key |
| `remoteip` | `string` | No | User's IP address |
| `idempotencyKey` | `string` | No | Unique request identifier |
| `sandbox` | `boolean` | No | Enable sandbox mode |
## Advanced Usage
### With Form Submission
```tsx
import { Turnstile } from "next-turnstile";
export default function Form() {
const [token, setToken] = useState<string>();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!token) return;
const response = await fetch("/api/submit", {
method: "POST",
body: JSON.stringify({ token }),
headers: { "Content-Type": "application/json" },
});
// Handle response...
};
return (
<form onSubmit={handleSubmit}>
<input type="email" required />
<Turnstile
siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}
onVerify={setToken}
/>
<button type="submit" disabled={!token}>
Submit
</button>
</form>
);
}
```
### Server Action Validation
```tsx
import { validateTurnstileToken } from "next-turnstile";
async function submitForm(formData: FormData) {
"use server";
const token = formData.get("cf-turnstile-response");
if (!token || typeof token !== "string") {
return { error: "No token provided" };
}
const result = await validateTurnstileToken({
token,
secretKey: process.env.TURNSTILE_SECRET_KEY!,
});
if (!result.success) {
return { error: "Invalid token" };
}
// Process form submission...
}
```
### Development Mode
During development, you can use sandbox mode to test without real credentials:
```tsx
<Turnstile
siteKey="1x00000000000000000000AA"
sandbox={process.env.NODE_ENV === "development"}
onVerify={handleVerify}
/>
```
### Dark Mode Support
```tsx
<Turnstile
siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}
theme="dark"
onVerify={handleVerify}
/>
```
### With Custom Styling
```tsx
<Turnstile
siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}
className="my-turnstile-widget"
onVerify={handleVerify}
/>
<style>
.my-turnstile-widget {
margin: 1rem 0;
/* Note: Internal widget styling is limited by Turnstile */
}
</style>
```
## Development and Contributing
1. Clone the repository
2. Install dependencies:
```bash
pnpm install
```
3. Start development:
```bash
pnpm dev
```
## License
MIT ยฉ Jed Patterson
## Credits
Built with โค๏ธ using:
- [Next.js](https://nextjs.org)
- [Cloudflare Turnstile](https://developers.cloudflare.com/turnstile)
- [TypeScript](https://www.typescriptlang.org)