svelte-turnstile

repository·main·Indexed 42 days ago

https://github.com/ghostdevv/svelte-turnstile

A Svelte wrapper for Cloudflare Turnstile CAPTCHA, providing bot protection for Svelte, SvelteKit, and Svelte 5 projects. Version 0.11.0 includes the Turnstile component for rendering widgets, handling lifecycle events like callback and error, and integrating with SvelteKit Form Actions.

Tokens
2.1K
Snippets
7
Records
10
Agent score
51%

What's inside svelte-turnstile

  1. Validate CAPTCHA tokens on the server

    main

    To prevent forgery, you must validate the Turnstile token on your server using Cloudflare's siteverify endpoint.

    If using a standard HTML form, the token is available via the responseFieldName (default: cf-turnstile-response). If using client-side logic, capture the token via the on:callback event.

    interface TokenValidateResponse {
    	'error-codes': string[];
    	success: boolean;
    	action: string;
    	cdata: string;
    }
    
    async function validateToken(token: string, secret: string) {
    	const response = await fetch(
    		'https://challenges.cloudflare.com/turnstile/v0/siteverify',
    		{
    			method: 'POST',
    			headers: {
    				'content-type': 'application/json',
    			},
    			body: JSON.stringify({
    				response: token,
    				secret: secret,
    			}),
    		},
    	);
    
    	const data: TokenValidateResponse = await response.json();
    
    	return {
    		success: data.success,
    		error: data['error-codes']?.length ? data['error-codes'][0] : null,
    	};
    }
  2. Integrate Turnstile with SvelteKit Form Actions (Svelte 5)

    main

    In SvelteKit, you can use Turnstile within a form and validate the token in a server-side action.

    Client Side (routes/login/+page.svelte):

    <script>
    	import { Turnstile } from 'svelte-turnstile';
    	let { form } = $props();
    </script>
    
    {#if form?.error}
    	<p>{form?.error}</p>
    {/if}
    
    <form method="POST" action="/login">
    	<Turnstile siteKey="SITE_KEY" theme="dark" />
    </form>

    Server Side (routes/login/+page.server.js):

    // Use the validateToken function defined in the documentation
    export const actions = {
    	default: async ({ request }) => {
    		const data = await request.formData();
    		const token = data.get('cf-turnstile-response');
    		const SECRET_KEY = '...'; // Use environment variables for secrets
    
    		const { success, error } = await validateToken(token, SECRET_KEY);
    
    		if (!success) {
    			return { error: error || 'Invalid CAPTCHA' };
    		}
    
    		// Proceed with logic if valid
    	},
    };
  3. Reset the Turnstile widget

    main

    You can manually reset the Turnstile widget by binding to the reset prop. This is useful when you need to clear the widget after a form submission or error.

    <script lang="ts">
    	let reset = $state<() => void>();
    </script>
    
    <button onclick={() => reset?.()}> Reset </button>
    
    <Turnstile bind:reset />
  4. Configure Turnstile component props

    main

    The Turnstile component accepts several props to customize its behavior and appearance:

    PropTypeDescriptionDefault
    siteKeystringSite key for your website (Required)-
    theme'light' | 'dark' | 'auto'Colour theme of the widget'auto'
    size'normal' | 'flexible' | 'invisible' | 'compact'Size of the widget'normal'
    actionstringString to differentiate widgets, returned on validation-
    cDatastringCustomer data attached to a challenge, returned on validation-
    tabIndexnumberAccessibility index0
    responseFieldbooleanIf true, the response token is a property on the form datatrue
    responseFieldNamestringThe name of the input in form data'cf-turnstile-response'
    retry'auto' | 'never'Whether to automatically retry obtaining a token'auto'
    retryIntervalnumberTime between retries in milliseconds8000
    languageSupportedLanguage | 'auto'Language for the widget'auto'
    execution'render' | 'execute'When to obtain the token'render'
    appearance'always' | 'execute' | 'interaction-only'When the widget is visible'always'

    Note on Deprecated Props:

    • Use responseField instead of forms.
    • Use responseFieldName instead of formsField.
  5. Handle Turnstile events

    main

    The Turnstile component emits several events to communicate widget state:

    EventDataDescription
    callback{ token: string; preClearanceObtained: boolean; }Emitted when a user passes a challenge
    error{ code: string }Emitted when a user fails verification
    expired{}Emitted when a challenge expires and does not reset the widget
    timeout{}Emitted when a challenge expires and does reset the widget
    before-interactive{}Emitted before the challenge enters interactive mode
    after-interactive{}Emitted when the challenge has left interactive mode
    unsupported{}Emitted when the client/browser is not supported

    Note on Deprecated Events:

    • Use on:callback instead of on:turnstile-callback.
    • Use on:error instead of on:turnstile-error.
    • Use on:timeout instead of on:turnstile-timeout.
    • Use on:expired instead of on:turnstile-expired.
  6. Handle Turnstile events and callbacks

    main

    The svelte-turnstile component emits several events that allow you to react to the lifecycle of the Cloudflare Turnstile challenge.

    Note on Deprecated Events: Several older event names are deprecated. You should use the new event names listed below:

    • Use callback instead of turnstile-callback.
    • Use error instead of turnstile-error.
    • Use expired instead of turnstile-expired.
    • Use timeout instead of turnstile-timeout.

    Available Events:

    EventPayloadDescription
    callback{ token: string; preClearanceObtained: boolean }Invoked upon successful challenge completion.
    error{ code: string }Invoked when an error occurs (e.g., network error). See Cloudflare Client-side errors for specific codes.
    expired{}Invoked when the token expires and the widget does not reset.
    timeout{}Invoked when the challenge expires.
    before-interactive{}Invoked before the challenge enters interactive mode.
    after-interactive{}Invoked when the challenge has left interactive mode.
    unsupported{}Invoked when the current client or browser is not supported.
    // Example of listening to events in a Svelte component
    <Turnstile 
      on:callback={(e) => console.log('Token:', e.detail.token)} 
      on:error={(e) => console.error('Error code:', e.detail.code)} 
    />
  7. Use the Turnstile component

    main

    The Turnstile component is the primary entry point for integrating Cloudflare Turnstile into a Svelte application. It provides a wrapper around the Turnstile widget, allowing you to render the CAPTCHA and handle its lifecycle via props and events.

    <script>
      import { Turnstile } from 'svelte-turnstile';
    </script>
    
    <Turnstile siteKey="YOUR_SITE_KEY" />