### Install Wrangler (Global)
Source: https://developers.cloudflare.com/turnstile/spin
Install Wrangler globally for use in any project.
```bash
npm install -g wrangler
```
--------------------------------
### Complete explicit rendering example
Source: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering
A full HTML example demonstrating explicit rendering of a Turnstile widget within a form. It includes basic setup and error handling callbacks.
```html
Explicit Rendering
```
--------------------------------
### Direct API Call Example (Widget Creation)
Source: https://developers.cloudflare.com/turnstile/spin/index.md
Example of creating a Turnstile widget using the Cloudflare API.
```bash
curl -X POST "https://api.cloudflare.com/client/v4/accounts/{id}/challenges/widgets" \
--header "Authorization: Bearer " \
--header "Content-Type: application/json" \
--data '{"name": "my-widget", "domain": "example.com", "mode": "non-interactive"}'
```
--------------------------------
### Install Turnstile Pages Plugin with bun
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Install the Turnstile Pages Plugin using bun.
```bash
bun add @cloudflare/pages-plugin-turnstile
```
--------------------------------
### Direct API Call Example (Worker Upload)
Source: https://developers.cloudflare.com/turnstile/spin/index.md
Example of uploading a Worker script using the Cloudflare API.
```bash
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{id}/workers/scripts/{script_name}" \
--header "Authorization: Bearer " \
--form "content=@"
```
--------------------------------
### Install cf-terraforming Tool
Source: https://developers.cloudflare.com/turnstile/get-started/widget-management/terraform
Install the `cf-terraforming` tool, which is used to import existing Cloudflare resources into Terraform state.
```bash
go install github.com/cloudflare/cf-terraforming/cmd/cf-terraforming@latest
```
--------------------------------
### Install Turnstile Skill for OpenCode
Source: https://developers.cloudflare.com/turnstile/spin/index.md
Installs the Turnstile skill locally for OpenCode by downloading the index.md file from the Cloudflare Turnstile documentation.
```bash
# OpenCode
mkdir -p .opencode/skills/turnstile-spin && \
curl -sSL https://developers.cloudflare.com/turnstile/spin/index.md \
-o .opencode/skills/turnstile-spin/SKILL.md
```
--------------------------------
### Install Turnstile Pages Plugin with npm
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Install the Turnstile Pages Plugin using npm.
```bash
npm i @cloudflare/pages-plugin-turnstile
```
--------------------------------
### Check Wrangler Version
Source: https://developers.cloudflare.com/turnstile/spin
Verify if the Wrangler CLI is installed. If not, instructions are provided for installation.
```bash
npx wrangler --version
```
--------------------------------
### Install Wrangler (Node Project)
Source: https://developers.cloudflare.com/turnstile/spin
Install Wrangler as a development dependency for a Node.js project.
```bash
npm install --save-dev wrangler
```
--------------------------------
### Install Turnstile Pages Plugin with yarn
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Install the Turnstile Pages Plugin using yarn.
```bash
yarn add @cloudflare/pages-plugin-turnstile
```
--------------------------------
### Install Turnstile Pages Plugin with pnpm
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Install the Turnstile Pages Plugin using pnpm.
```bash
pnpm add @cloudflare/pages-plugin-turnstile
```
--------------------------------
### Install Wrangler Globally
Source: https://developers.cloudflare.com/turnstile/spin
Use this command to install the Wrangler CLI globally for use in any project type.
```bash
#!/usr/bin/env bash
npm install -g wrangler
```
--------------------------------
### Install Turnstile Skill for Cursor
Source: https://developers.cloudflare.com/turnstile/spin/index.md
Installs the Turnstile skill locally for Cursor by downloading the index.md file from the Cloudflare Turnstile documentation.
```bash
# Cursor
mkdir -p .cursor/rules && \
curl -sSL https://developers.cloudflare.com/turnstile/spin/index.md \
-o .cursor/rules/turnstile-spin.md
```
--------------------------------
### Example Report Summary
Source: https://developers.cloudflare.com/turnstile/spin
This is an example of a final summary report after completing the Turnstile integration. It lists created resources, validated checks, and next steps.
```text
Turnstile Spin: complete.
Created:
• Widget "myproject (Spin)", sitekey 0x4AAAAAA...
• Worker https://turnstile-siteverify-myproject.example.workers.dev
• Frontend snippets at:
- app/(auth)/signup/page.tsx
- app/(auth)/login/page.tsx
- app/contact/page.tsx
• Skill saved at .claude/skills/turnstile-spin/SKILL.md
Validated:
✓ Worker /health returns 200
✓ Worker handles a dummy token with a structured error
✓ Widget hostname matches example.com
Next:
• Open one of the protected forms in a browser, solve the widget, and
confirm the form submits successfully.
• If you need to protect a new form later, prompt: "Use the
turnstile-spin skill to add Turnstile to ."
```
--------------------------------
### Install Turnstile Bundle with Degit
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Installs the canonical Turnstile bundle from cloudflare/skills using degit. This script handles argument parsing, directory creation, fetching the bundle, making scripts executable, and reporting the installation status.
```bash
#!/usr/bin/env bash
# Installs the canonical bundle from cloudflare/skills via degit.
# Writes SKILL.md, scripts/, references/, templates/, tests/ into $TARGET_DIR.
set -uo pipefail
PATH_ARG=""
while [[ $# -gt 0 ]]; do
case $1 in
--path) PATH_ARG="$2"; shift 2 ;;
*) echo "persist-skill: unknown arg $1" >&2; exit 2 ;;
esac
done
: "${PATH_ARG:?--path required}"
TARGET_DIR=$(dirname "$PATH_ARG")
mkdir -p "$TARGET_DIR"
# Install the canonical bundle from cloudflare/skills via degit. This writes
# SKILL.md, scripts/, references/, templates/, tests/ into $TARGET_DIR.
if ! npx --yes degit cloudflare/skills/skills/turnstile-spin "$TARGET_DIR" >/dev/null 2>&1; then
echo "persist-skill: degit failed; cannot fetch cloudflare/skills/skills/turnstile-spin." >&2
echo "persist-skill: ensure your network can reach github.com and try again, or install manually." >&2
echo "{\"status\":\"error\",\"reason\":\"degit_failed\"}"
exit 1
fi
if [ ! -f "$TARGET_DIR/SKILL.md" ]; then
echo "persist-skill: bundle extracted but SKILL.md is missing at $TARGET_DIR/SKILL.md." >&2
echo "{\"status\":\"error\",\"reason\":\"skill_missing\"}"
exit 1
fi
# Make scripts executable so the agent can invoke them directly.
if [ -d "$TARGET_DIR/scripts" ]; then
chmod +x "$TARGET_DIR/scripts"/*.sh 2>/dev/null || true
fi
scripts_list=$(ls "$TARGET_DIR/scripts" 2>/dev/null | sed 's/.*/\"&\"/' | paste -sd, -)
echo "persist-skill: wrote bundle to $TARGET_DIR" >&2
echo "{\"status\":\"ok\",\"path\":\"$PATH_ARG\",\"bundle_root\":\"$TARGET_DIR\",\"scripts\":[$scripts_list]}"
exit 0
```
--------------------------------
### Client-side testing with dummy sitekey
Source: https://developers.cloudflare.com/turnstile/troubleshooting/testing
Replace your production sitekey with a test sitekey for client-side testing. This example shows how to use a visible widget test sitekey.
```html
```
```html
```
--------------------------------
### Install Wrangler for Node.js Projects
Source: https://developers.cloudflare.com/turnstile/spin
Use this command to install the Wrangler CLI as a development dependency in a Node.js project.
```bash
#!/usr/bin/env bash
npm install --save-dev wrangler
```
--------------------------------
### Server-Side Integration for Rendering Forms
Source: https://developers.cloudflare.com/turnstile/tutorials/excluding-turnstile-from-e2e-tests
Integrate Turnstile credentials into your server-side rendering logic. This example shows how to get the correct sitekey using `getTurnstileCredentials` and pass it to the form template.
```javascript
app.get('/your-form', (req, res) => {
const { sitekey } = getTurnstileCredentials(req);
res.render('form', { sitekey });
});
```
--------------------------------
### Example User Phrasing for Existing Widget
Source: https://developers.cloudflare.com/turnstile/spin
Users may phrase their need for assistance with an existing Turnstile widget in various ways. This example shows typical user statements.
```text
"I already have a Turnstile sitekey but siteverify never worked, can you help wire it up?"
"Set up Spin against my existing widget `0x4AAAAAAA...`"
```
--------------------------------
### Install Wrangler Globally
Source: https://developers.cloudflare.com/turnstile/spin
Use this command to install Wrangler globally if you are in a Node.js project and `npx wrangler` fails with 'command not found'.
```bash
npm install -g wrangler
```
--------------------------------
### Client-Side Testing with Visible Widget
Source: https://developers.cloudflare.com/turnstile/troubleshooting/testing/index.md
Replace your production sitekey with a test sitekey for visible widget testing. This example uses the 'Always passes' test sitekey.
```html
```
--------------------------------
### Install Turnstile Spin Skill
Source: https://developers.cloudflare.com/turnstile/spin/index.md
Installs the canonical Turnstile Spin skill bundle from Cloudflare's GitHub repository using degit. Ensures the SKILL.md file is present and makes shell scripts executable.
```bash
#!/usr/bin/env bash
# Installs the canonical Turnstile Spin skill bundle from cloudflare/skills via degit.
# Writes SKILL.md, scripts/, references/, templates/, tests/ into $TARGET_DIR.
set -uo pipefail
PATH_ARG=""
while [[ $# -gt 0 ]]; do
case $1 in
--path) PATH_ARG="$2"; shift 2 ;;
*) echo "persist-skill: unknown arg $1" >&2; exit 2 ;;
esac
done
: "${PATH_ARG:?--path required}"
TARGET_DIR=$(dirname "$PATH_ARG")
mkdir -p "$TARGET_DIR"
# Install the canonical bundle from cloudflare/skills via degit. This writes
# SKILL.md, scripts/, references/, templates/, tests/ into $TARGET_DIR.
if ! npx --yes degit cloudflare/skills/skills/turnstile-spin "$TARGET_DIR" >/dev/null 2>&1; then
echo "persist-skill: degit failed; cannot fetch cloudflare/skills/skills/turnstile-spin."
echo "persist-skill: ensure your network can reach github.com and try again, or install manually."
echo "{"status":"error","reason":"degit_failed"}"
exit 1
fi
if [ ! -f "$TARGET_DIR/SKILL.md" ]; then
echo "persist-skill: bundle extracted but SKILL.md is missing at $TARGET_DIR/SKILL.md."
echo "{"status":"error","reason":"skill_missing"}"
exit 1
fi
# Make scripts executable so the agent can invoke them directly.
if [ -d "$TARGET_DIR/scripts" ]; then
chmod +x "$TARGET_DIR/scripts"/*.sh 2>/dev/null || true
fi
scripts_list=$(ls "$TARGET_DIR/scripts" 2>/dev/null | sed 's/.*/"&"/' | paste -sd, -)
echo "persist-skill: wrote bundle to $TARGET_DIR" >&2
echo "{"status":"ok","path":"$PATH_ARG","bundle_root":"$TARGET_DIR","scripts":[$scripts_list]}"
exit 0
```
--------------------------------
### Install Wrangler Locally
Source: https://developers.cloudflare.com/turnstile/spin
If you are in a non-Node.js project (e.g., Hugo, vanilla HTML), install Wrangler as a development dependency locally.
```bash
npm init -y
npm install --save-dev wrangler
```
--------------------------------
### Basic Explicit Rendering Example
Source: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/index.md
Demonstrates a basic HTML structure with Turnstile's explicit rendering. The widget is rendered when the window loads.
```html
Explicit Rendering
```
--------------------------------
### Basic validation example (JavaScript)
Source: https://developers.cloudflare.com/turnstile/get-started/server-side-validation
An example of how to call the Siteverify API using JavaScript's fetch API to validate a Turnstile token.
```javascript
const SECRET_KEY = "your-secret-key";
async function validateTurnstile(token, remoteip) {
try {
const response = await fetch(
"https://challenges.cloudflare.com/turnstile/v0/siteverify",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
secret: SECRET_KEY,
response: token,
remoteip: remoteip,
}),
},
);
const result = await response.json();
return result;
} catch (error) {
console.error("Turnstile validation error:", error);
return { success: false, "error-codes": ["internal-error"] };
}
}
```
--------------------------------
### Install Turnstile Skill for Claude Code
Source: https://developers.cloudflare.com/turnstile/spin/index.md
Installs the Turnstile skill locally for Claude Code by downloading the index.md file from the Cloudflare Turnstile documentation.
```bash
# Claude Code
mkdir -p .claude/skills/turnstile-spin && \
curl -sSL https://developers.cloudflare.com/turnstile/spin/index.md \
-o .claude/skills/turnstile-spin/SKILL.md
```
--------------------------------
### Environment Configuration for Turnstile Keys
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Set up different Turnstile sitekeys and secret keys for various environments (development, test, production) using .env files. This example shows the structure for each environment.
```bash
# .env.development
TURNSTILE_SITEKEY=1x00000000000000000000AA
TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA
# .env.test
TURNSTILE_SITEKEY=2x00000000000000000000AB
TURNSTILE_SECRET_KEY=2x0000000000000000000000000000000AA
# .env.production
TURNSTILE_SITEKEY=your-real-sitekey
TURNSTILE_SECRET_KEY=your-real-secret-key
```
--------------------------------
### Validate Turnstile Setup
Source: https://developers.cloudflare.com/turnstile/spin
Run a series of checks to validate the Turnstile integration, including authentication, widget configuration, and worker deployment.
```bash
scripts/validate.sh
```
--------------------------------
### Client-Side Testing with Invisible Widget
Source: https://developers.cloudflare.com/turnstile/troubleshooting/testing/index.md
Replace your production sitekey with a test sitekey for invisible widget testing. This example uses the 'Always passes' invisible test sitekey.
```html
```
--------------------------------
### Complete HTML Example for Contact Form
Source: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/index.md
A full HTML document demonstrating Turnstile integration in a contact form. Ensure the Turnstile API script is included in the head.
```html
Implicit Rendering with Cloudflare Turnstile
Contact Us
```
--------------------------------
### Explicit Rendering Setup
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Load the Turnstile script with render=explicit and use JavaScript to call turnstile.render() for programmatic widget creation. Configure using a JavaScript object.
```html
```
--------------------------------
### Turnstile Pages Plugin Usage Example
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Example of using the Turnstile Pages Plugin in a Cloudflare Pages Function for request validation. It demonstrates how to configure the plugin with a secret key and process validated requests.
```typescript
import turnstilePlugin from "@cloudflare/pages-plugin-turnstile";
/**
* POST /api/submit-with-plugin
*/
export const onRequestPost = [
turnstilePlugin({
// This is the demo secret key. In prod, we recommend you store
// your secret key(s) safely.
secret: "0x4AAAAAAASh4E5cwHGsTTePnwcPbnFru6Y",
}),
// Alternatively, this is how you can use a secret key which has been stored as an environment variable
// (async (context) => {
// return turnstilePlugin({secret: context.env.SECRET_KEY})(context)
// }),
async (context) => {
// Request has been validated as coming from a human
const formData = await context.request.formData();
// Additional solve metadata data is available at context.data.turnstile
return new Response(
`Successfully verified! ${JSON.stringify(context.data.turnstile)}`,
);
},
];
```
--------------------------------
### Turnstile Widget with Tracking Parameters
Source: https://developers.cloudflare.com/turnstile/additional-configuration/hostname-management/any-hostname
Example of embedding a Turnstile widget with 'action' and 'cData' parameters for tracking widget usage sources and deployment locations.
```html
```
--------------------------------
### Create Turnstile Widget via Cloudflare API
Source: https://developers.cloudflare.com/turnstile/llms-full.txt
Example using curl to create a Turnstile widget using the Cloudflare API.
```bash
curl --request POST --url https://api.cloudflare.com/client/v4/accounts/{id}/challenges/widgets --header "Authorization: Bearer " --header "Content-Type: application/json" --data "{\"name\":\"myproject (Spin)\"}"
```
--------------------------------
### Next.js Signup Form with Turnstile Callback
Source: https://developers.cloudflare.com/turnstile/spin
Another Next.js example using `onLoad` for the Turnstile callback. This approach sets the `onTurnstileSuccess` function when the Turnstile script is loaded.
```javascript
import Script from "next/script";
import { useState } from "react";
declare global {
interface Window {
onTurnstileSuccess?: (token: string) => void;
}
}
export default function SignupPage() {
const [token, setToken] = useState("");
const [error, setError] = useState("");
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError("");
const verify = await fetch("https://YOUR_WORKER_URL/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token }),
});
const { success } = await verify.json();
if (!success) {
setError("Verification failed. Try again.");
return;
}
// On success, run the user's existing submit logic — whatever it was.
/* existing submit logic */
}
return (
<>