Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/turnstile/configuration.md
1# Configuration23## Script Loading45### Basic (Implicit Rendering)6```html7<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>8```9Automatically renders widgets with `class="cf-turnstile"` on page load.1011### Explicit Rendering12```html13<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>14```15Manual control over when/where widgets render via `window.turnstile.render()`.1617### With Load Callback18```html19<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=myCallback"></script>20<script>21function myCallback() {22// API ready23window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY' });24}25</script>26```2728### Compatibility Mode29```html30<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?compat=recaptcha"></script>31```32Provides `grecaptcha` API for Google reCAPTCHA drop-in replacement.3334## Widget Configuration3536### Complete Options Object3738```javascript39{40// Required41sitekey: 'YOUR_SITE_KEY', // Widget sitekey from dashboard4243// Callbacks44callback: (token) => {}, // Success - token ready45'error-callback': (code) => {}, // Error occurred46'expired-callback': () => {}, // Token expired (>5min)47'timeout-callback': () => {}, // Challenge timeout48'before-interactive-callback': () => {}, // Before showing checkbox49'after-interactive-callback': () => {}, // After user interacts50'unsupported-callback': () => {}, // Browser doesn't support Turnstile5152// Appearance53theme: 'auto', // 'light' | 'dark' | 'auto'54size: 'normal', // 'normal' | 'compact' | 'flexible'55tabindex: 0, // Tab order (accessibility)56language: 'auto', // ISO 639-1 code or 'auto'5758// Behavior59execution: 'render', // 'render' (auto) | 'execute' (manual)60appearance: 'always', // 'always' | 'execute' | 'interaction-only'61retry: 'auto', // 'auto' | 'never'62'retry-interval': 8000, // Retry interval (ms), default 800063'refresh-expired': 'auto', // 'auto' | 'manual' | 'never'6465// Form Integration66'response-field': true, // Add hidden input (default: true)67'response-field-name': 'cf-turnstile-response', // Hidden input name6869// Analytics & Data70action: 'login', // Action name (for analytics)71cData: 'user-session-123', // Custom data (returned in siteverify)72}73```7475### Key Options Explained7677**`execution`:**78- `'render'` (default): Challenge starts immediately on render79- `'execute'`: Wait for `turnstile.execute()` call8081**`appearance`:**82- `'always'` (default): Widget always visible83- `'execute'`: Hidden until `execute()` called84- `'interaction-only'`: Hidden until user interaction needed8586**`refresh-expired`:**87- `'auto'` (default): Auto-refresh expired tokens88- `'manual'`: App must call `reset()` after expiry89- `'never'`: No refresh, expired-callback triggered9091**`retry`:**92- `'auto'` (default): Auto-retry failed challenges93- `'never'`: Don't retry, trigger error-callback9495## HTML Data Attributes9697For implicit rendering, use data attributes on `<div class="cf-turnstile">`:9899| JavaScript Property | HTML Data Attribute | Example |100|---------------------|---------------------|---------|101| `sitekey` | `data-sitekey` | `data-sitekey="YOUR_KEY"` |102| `action` | `data-action` | `data-action="login"` |103| `cData` | `data-cdata` | `data-cdata="session-123"` |104| `callback` | `data-callback` | `data-callback="onSuccess"` |105| `error-callback` | `data-error-callback` | `data-error-callback="onError"` |106| `expired-callback` | `data-expired-callback` | `data-expired-callback="onExpired"` |107| `timeout-callback` | `data-timeout-callback` | `data-timeout-callback="onTimeout"` |108| `theme` | `data-theme` | `data-theme="dark"` |109| `size` | `data-size` | `data-size="compact"` |110| `tabindex` | `data-tabindex` | `data-tabindex="0"` |111| `response-field` | `data-response-field` | `data-response-field="false"` |112| `response-field-name` | `data-response-field-name` | `data-response-field-name="token"` |113| `retry` | `data-retry` | `data-retry="never"` |114| `retry-interval` | `data-retry-interval` | `data-retry-interval="5000"` |115| `language` | `data-language` | `data-language="en"` |116| `execution` | `data-execution` | `data-execution="execute"` |117| `appearance` | `data-appearance` | `data-appearance="interaction-only"` |118| `refresh-expired` | `data-refresh-expired` | `data-refresh-expired="manual"` |119120**Example:**121```html122<div class="cf-turnstile"123data-sitekey="YOUR_SITE_KEY"124data-theme="dark"125data-callback="onTurnstileSuccess"126data-error-callback="onTurnstileError"></div>127```128129## Content Security Policy130131Add these directives to CSP header/meta tag:132133```134script-src https://challenges.cloudflare.com;135frame-src https://challenges.cloudflare.com;136```137138**Full Example:**139```html140<meta http-equiv="Content-Security-Policy"141content="default-src 'self';142script-src 'self' https://challenges.cloudflare.com;143frame-src https://challenges.cloudflare.com;">144```145146## Framework-Specific Setup147148### React149```bash150npm install @marsidev/react-turnstile151```152```jsx153import Turnstile from '@marsidev/react-turnstile';154155<Turnstile156siteKey="YOUR_SITE_KEY"157onSuccess={(token) => console.log(token)}158/>159```160161### Vue162```bash163npm install vue-turnstile164```165```vue166<template>167<VueTurnstile site-key="YOUR_SITE_KEY" @success="onSuccess" />168</template>169<script setup>170import VueTurnstile from 'vue-turnstile';171</script>172```173174### Svelte175```bash176npm install svelte-turnstile177```178```svelte179<script>180import Turnstile from 'svelte-turnstile';181</script>182<Turnstile siteKey="YOUR_SITE_KEY" on:turnstile-callback={handleToken} />183```184185### Next.js (App Router)186```tsx187// app/components/TurnstileWidget.tsx188'use client';189import { useEffect, useRef } from 'react';190191export default function TurnstileWidget({ sitekey, onSuccess }) {192const ref = useRef<HTMLDivElement>(null);193194useEffect(() => {195if (ref.current && window.turnstile) {196const widgetId = window.turnstile.render(ref.current, {197sitekey,198callback: onSuccess199});200return () => window.turnstile.remove(widgetId);201}202}, [sitekey, onSuccess]);203204return <div ref={ref} />;205}206```207208## Cloudflare Pages Plugin209210```bash211npm install @cloudflare/pages-plugin-turnstile212```213214```typescript215// functions/_middleware.ts216import turnstilePlugin from '@cloudflare/pages-plugin-turnstile';217218export const onRequest = turnstilePlugin({219secret: 'YOUR_SECRET_KEY',220onError: () => new Response('CAPTCHA failed', { status: 403 })221});222```