@svelte-put/cloudflare-turnstile

GitHub Github

action for rendering Cloudflare turnstile into HTML node

@svelte-put/cloudflare-turnstile @svelte-put/cloudflare-turnstile @svelte-put/cloudflare-turnstile @svelte-put/cloudflare-turnstile

Still on Svelte 4? See the old docs site here.

Introduction

This implementation of Cloudflare Turnstile utilizes Svelte action. If you are looking for a component-oriented solution, check out ghostdevv/svelte-turnstile instead.

Installation

npm install --save-dev @svelte-put/cloudflare-turnstile
pnpm add -D @svelte-put/cloudflare-turnstile
yarn add -D @svelte-put/cloudflare-turnstile

New to Svelte 5? See Migration Guides.

Quick Start

Example

Captured Token:

<script lang="ts">
	import { turnstile } from '@svelte-put/cloudflare-turnstile';

	// assume using SvelteKit and the '$env/static/public' module is available
	import { PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY } from '$env/static/public';

	let token = $state('');
	$inspect(token);
</script>

<div
	use:turnstile
	turnstile-sitekey={PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY}
	turnstile-theme="auto"
	turnstile-size="normal"
	turnstile-language="en"
	turnstile-response-field-name="turnstile"
	turnstile-response-field
	onturnstile={(e) => (token = e.detail.token)}
></div>
<p>
	Captured Token: <span class="hl-success px-2">{token ?? 'pending'}</span>
</p>
PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY="1x00000000000000000000AA"

Configuration Attributes

As seen in Quick Start, @svelte-put/cloudflare-turnstile can be customized by adding turnstile-* attributes, where * are properties as described in Cloudflare Turnstile's client configuration documentation, except for *-callback properties, which can be specified via Svelte event handler syntax onturnstile* (more in Events).

If you have Typescript language server set up correctly, you should get autocomplete / intellisense for these turnstile* attributes.

The turnstile-sitekey is the only mandatory property. In Quick Start, it is set via environment variable PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY, assuming usage with SvelteKit. See more in SvelteKit's docs on static public env.

<div
  use:turnstile
  turnstile-sitekey="1x00000000000000000000AA"
  turnstile-theme="auto"
  turnstile-size="normal"
  turnstile-language="en"
  turnstile-response-field-name="turnstile"
  turnstile-response-field
  turnstile-action="customer-feedback"
  turnstile-cData="customer-id-123"
  turnstile-execution="render"
  turnstile-tabindex="0"
  turnstile-retry="auto"
  turnstile-retry-interval="8000"
  turnstile-refresh-expired="auto"
  turnstile-refresh-timeout="auto"
  turnstile-appearance="always"
  turnstile-feedback-enabled
></div>

Additionally, you may provide the turnstile-script-src attribute, which specifies the URL to load Turnstile script from. The default URL is shown in below code snippet.

<div
  use:turnstile
  turnstile-sitekey="1x00000000000000000000AA"
  turnstile-script-src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
></div>

Finally, there are two readonly attributes that will be dynamically added by the turnstile at runtime: turnstile-widget-id is one returned from Cloudflare Turnstile API, and turnstile-rendered is added if the widget is successfully rendered.

<div [...truncated...] turnstile-widget-id="..." turnstile-rendered></div>

Events

As seen Quick Start, turnstile is a CustomEvent invoked upon success of the challenge. The event detail contains a token that should be sent to backend for validation. other turnstile* CustomEvents are mapped directly to those found in Cloudflare Turnstile's documentation, without space or hyphen.

type TurnstileEventDetail<T extends Record<string, any> = Record<string, never>> = {
	widgetId: string;
	turnstile: Turnstile;
} & T;

type TurnstileEventAttributes = {
	'onturnstile'?: (event: CustomEvent<TurnstileEventDetail<{ token: string }>>) => void;
	'onturnstiletrror'?: (event: CustomEvent<TurnstileEventDetail<{ code: string }>>) => void;
	'onturnstiletxpired'?: (event: CustomEvent<TurnstileEventDetail>) => void;
	'onturnstileteforeinteractive'?: (event: CustomEvent<TurnstileEventDetail>) => void;
	'onturnstiletfterinteractive'?: (event: CustomEvent<TurnstileEventDetail>) => void;
	'onturnstiletnsupported'?: (event: CustomEvent<TurnstileEventDetail>) => void;
	'onturnstiletimeout'?: (event: CustomEvent<TurnstileEventDetail>) => void;
};

Notice the event detail provides access to widgetId and the turnstile object, which is helpful if you need to execute custom JS such as reset the widget or check if it is expired.

<script lang="ts">
	import { turnstile } from '@svelte-put/cloudflare-turnstile';
	import type { TurnstileEventAttributes } from '@svelte-put/cloudflare-turnstile';

	const handleTurnstile: TurnstileEventAttributes['onturnstile'] = (e) => {
		const { token, turnstile, widgetId } = e.detail;
		// ...
	};
</script>

<div use:turnstile turnstile-sitekey="1x00000000000000000000AA" onturnstile={handleTurnstile}>

The turnstile object has the following interface:

type Turnstile = {
	render: (element: string | HTMLElement, config: TurnstileConfig) => string;
	reset: (widgetId: string) => void;
	remove: (widgetId: string) => void;
	getResponse: (widgetId: string) => string | undefined;
	isExpired: (widgetId: string) => boolean;
	execute: (container: string | HTMLElement, config?: TurnstileConfig) => void;
};

Backend Integration (with SvelteKit)

>

Coming soon...

Migration Guides

V0 -> V1 (Svelte 5 in Runes mode)

When migrating to V1, you just need to remove any colon : in event attributes:

<div
  use:turnstile
  turnstile-sitekey="1x00000000000000000000AA"
  on:turnstile={handleTurnstile}
  onturnstile={handleTurnstile}
>

Happy turning in style! 👨‍💻

Edit this page on Github