Documentation Index
Fetch the complete documentation index at: https://mintlify.com/marsidev/react-turnstile/llms.txt
Use this file to discover all available pages before exploring further.
Interface
interface ScriptOptions {
nonce?: string
defer?: boolean
async?: boolean
appendTo?: 'head' | 'body'
id?: string
onLoadCallbackName?: string
onError?: () => void
crossOrigin?: string
}
Usage
Pass these options via the scriptOptions prop:
<Turnstile
siteKey="your-site-key"
scriptOptions={{
defer: true,
async: true,
nonce: 'random-nonce-value'
}}
/>
Options
nonce
string
default:"undefined"
Custom nonce for the injected script. Used for Content Security Policy (CSP) compliance.scriptOptions={{ nonce: 'random-nonce-value' }}
Example with CSP:<meta http-equiv="Content-Security-Policy"
content="script-src 'nonce-random-nonce-value'">
Whether to set the injected script as deferred. Deferred scripts execute after the document has been parsed.scriptOptions={{ defer: true }}
Whether to set the injected script as async. Async scripts execute as soon as they’re loaded.scriptOptions={{ async: true }}
appendTo
'head' | 'body'
default:"'head'"
Where to inject the script in the document.
'head': Appends to <head> element
'body': Appends to <body> element
scriptOptions={{ appendTo: 'body' }}
id
string
default:"'cf-turnstile-script'"
Custom ID for the injected script element. Useful for identifying the script in the DOM.scriptOptions={{ id: 'my-turnstile-script' }}
onLoadCallbackName
string
default:"'onloadTurnstileCallback'"
Custom name for the global onload callback function. This function is called when the Turnstile script loads.scriptOptions={{ onLoadCallbackName: 'myCustomCallback' }}
onError
() => void
default:"undefined"
Callback invoked when the script fails to load (e.g., Cloudflare has an outage).scriptOptions={{
onError: () => {
console.error('Failed to load Turnstile script')
// Show fallback UI
}
}}
crossOrigin
string
default:"undefined"
Custom crossOrigin attribute for the injected script.Accepted values: 'anonymous', 'use-credentials'scriptOptions={{ crossOrigin: 'anonymous' }}
Common Scenarios
Content Security Policy (CSP)
When using CSP, you need to provide a nonce:
function MyComponent({ nonce }: { nonce: string }) {
return (
<Turnstile
siteKey="your-site-key"
scriptOptions={{ nonce }}
/>
)
}
Manual Script Injection
If you want to inject the script manually:
import { useEffect } from 'react'
import Turnstile, { injectTurnstileScript } from '@marsidev/react-turnstile'
function MyComponent() {
useEffect(() => {
injectTurnstileScript({
scriptOptions: {
defer: false,
async: true,
appendTo: 'body'
}
})
}, [])
return (
<Turnstile
siteKey="your-site-key"
injectScript={false}
/>
)
}
Error Handling
Handle script loading errors gracefully:
import { useState } from 'react'
import Turnstile from '@marsidev/react-turnstile'
function MyComponent() {
const [scriptError, setScriptError] = useState(false)
if (scriptError) {
return <div>Turnstile is currently unavailable. Please try again later.</div>
}
return (
<Turnstile
siteKey="your-site-key"
scriptOptions={{
onError: () => setScriptError(true)
}}
/>
)
}
<Turnstile
siteKey="your-site-key"
scriptOptions={{
defer: true,
async: true,
appendTo: 'body' // Load after body content
}}
/>
Default Script URL
The Turnstile script is loaded from:
https://challenges.cloudflare.com/turnstile/v0/api.js
With query parameters:
onload: The callback function name
render: 'explicit' (controlled by the library)
Final URL example:
https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback&render=explicit
Constants
The following constants are exported and can be imported:
import {
SCRIPT_URL,
DEFAULT_SCRIPT_ID,
DEFAULT_ONLOAD_NAME
} from '@marsidev/react-turnstile'
console.log(SCRIPT_URL) // 'https://challenges.cloudflare.com/turnstile/v0/api.js'
console.log(DEFAULT_SCRIPT_ID) // 'cf-turnstile-script'
console.log(DEFAULT_ONLOAD_NAME) // 'onloadTurnstileCallback'
See Constants for all exported constants.