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/api.md
1# API Reference23## Client-Side JavaScript API45The Turnstile JavaScript API is available at `window.turnstile` after loading the script.67### `turnstile.render(container, options)`89Renders a Turnstile widget into a container element.1011**Parameters:**12- `container` (string | HTMLElement): CSS selector or DOM element13- `options` (TurnstileOptions): Configuration object (see [configuration.md](configuration.md))1415**Returns:** `string` - Widget ID for use with other API methods1617**Example:**18```javascript19const widgetId = window.turnstile.render('#my-container', {20sitekey: 'YOUR_SITE_KEY',21callback: (token) => console.log('Success:', token),22'error-callback': (code) => console.error('Error:', code)23});24```2526### `turnstile.reset(widgetId)`2728Resets a widget (clears token, resets challenge state). Useful when form validation fails.2930**Parameters:**31- `widgetId` (string): Widget ID from `render()`, or container element3233**Returns:** `void`3435**Example:**36```javascript37// Reset on form error38if (!validateForm()) {39window.turnstile.reset(widgetId);40}41```4243### `turnstile.remove(widgetId)`4445Removes a widget from the DOM completely.4647**Parameters:**48- `widgetId` (string): Widget ID from `render()`4950**Returns:** `void`5152**Example:**53```javascript54// Cleanup on navigation55window.turnstile.remove(widgetId);56```5758### `turnstile.getResponse(widgetId)`5960Gets the current token from a widget (if challenge completed).6162**Parameters:**63- `widgetId` (string): Widget ID from `render()`, or container element6465**Returns:** `string | undefined` - Token string, or undefined if not ready6667**Example:**68```javascript69const token = window.turnstile.getResponse(widgetId);70if (token) {71submitForm(token);72}73```7475### `turnstile.isExpired(widgetId)`7677Checks if a widget's token has expired (>5 minutes old).7879**Parameters:**80- `widgetId` (string): Widget ID from `render()`8182**Returns:** `boolean` - True if expired8384**Example:**85```javascript86if (window.turnstile.isExpired(widgetId)) {87window.turnstile.reset(widgetId);88}89```9091## Callback Signatures9293```typescript94type TurnstileCallback = (token: string) => void;95type ErrorCallback = (errorCode: string) => void;96type TimeoutCallback = () => void;97type ExpiredCallback = () => void;98type BeforeInteractiveCallback = () => void;99type AfterInteractiveCallback = () => void;100type UnsupportedCallback = () => void;101```102103## Siteverify API (Server-Side)104105**Endpoint:** `https://challenges.cloudflare.com/turnstile/v0/siteverify`106107### Request108109**Method:** POST110**Content-Type:** `application/json` or `application/x-www-form-urlencoded`111112```typescript113interface SiteverifyRequest {114secret: string; // Your secret key (never expose client-side)115response: string; // Token from cf-turnstile-response116remoteip?: string; // User's IP (optional but recommended)117idempotency_key?: string; // Unique key for idempotent validation118}119```120121**Example:**122```javascript123// Cloudflare Workers124const result = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {125method: 'POST',126headers: { 'Content-Type': 'application/json' },127body: JSON.stringify({128secret: env.TURNSTILE_SECRET,129response: token,130remoteip: request.headers.get('CF-Connecting-IP')131})132});133const data = await result.json();134```135136### Response137138```typescript139interface SiteverifyResponse {140success: boolean; // Validation result141challenge_ts?: string; // ISO timestamp of challenge142hostname?: string; // Hostname where widget was solved143'error-codes'?: string[]; // Error codes if success=false144action?: string; // Action name from widget config145cdata?: string; // Custom data from widget config146}147```148149**Example Success:**150```json151{152"success": true,153"challenge_ts": "2024-01-15T10:30:00Z",154"hostname": "example.com",155"action": "login",156"cdata": "user123"157}158```159160**Example Failure:**161```json162{163"success": false,164"error-codes": ["timeout-or-duplicate"]165}166```167168## Error Codes169170| Code | Cause | Solution |171|------|-------|----------|172| `missing-input-secret` | Secret key not provided | Include `secret` in request |173| `invalid-input-secret` | Secret key is wrong | Check secret key in dashboard |174| `missing-input-response` | Token not provided | Include `response` token |175| `invalid-input-response` | Token is invalid/malformed | Verify token from widget |176| `timeout-or-duplicate` | Token expired (>5min) or reused | Generate new token, validate once |177| `internal-error` | Cloudflare server error | Retry with exponential backoff |178| `bad-request` | Malformed request | Check JSON/form encoding |179180## TypeScript Types181182```typescript183interface TurnstileOptions {184sitekey: string;185action?: string;186cData?: string;187callback?: (token: string) => void;188'error-callback'?: (errorCode: string) => void;189'expired-callback'?: () => void;190'timeout-callback'?: () => void;191'before-interactive-callback'?: () => void;192'after-interactive-callback'?: () => void;193'unsupported-callback'?: () => void;194theme?: 'light' | 'dark' | 'auto';195size?: 'normal' | 'compact' | 'flexible';196tabindex?: number;197'response-field'?: boolean;198'response-field-name'?: string;199retry?: 'auto' | 'never';200'retry-interval'?: number;201language?: string;202execution?: 'render' | 'execute';203appearance?: 'always' | 'execute' | 'interaction-only';204'refresh-expired'?: 'auto' | 'manual' | 'never';205}206207interface Turnstile {208render(container: string | HTMLElement, options: TurnstileOptions): string;209reset(widgetId: string): void;210remove(widgetId: string): void;211getResponse(widgetId: string): string | undefined;212isExpired(widgetId: string): boolean;213execute(container?: string | HTMLElement, options?: TurnstileOptions): void;214}215216declare global {217interface Window {218turnstile: Turnstile;219onloadTurnstileCallback?: () => void;220}221}222```223224## Script Loading225226```html227<!-- Standard -->228<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>229230<!-- Explicit render mode -->231<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>232233<!-- With load callback -->234<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback"></script>235<script>236window.onloadTurnstileCallback = () => {237window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY' });238};239</script>240```