INTEGRITY Документация

Встраивание виджета

Как добавить виджет Turnstile на страницу с помощью неявной или явной отрисовки.

Turnstile предлагает два способа добавить виджет на страницу. Неявная отрисовка при загрузке страницы автоматически находит в вашем HTML контейнеры виджетов. Явный рендеринг даёт программный контроль и позволяет создавать виджеты в любой момент средствами JavaScript. Неявный рендеринг подходит для статических страниц, где формы существуют уже при загрузке. Явный рендеринг подходит для динамического содержимого и одностраничных приложений (SPA), где формы создаются после первоначальной загрузки страницы.

Возможность Неявная отрисовка Явный рендеринг
Простота настройки Простой, минимальный код Требуется дополнительный код JavaScript
Контроль над временем запуска Отрисовывается автоматически при загрузке страницы Полный контроль над моментом отрисовки
Сценарии использования Статическое содержимое Динамический или интерактивный контент
Настройка Ограничено атрибутами HTML Широкие возможности через JavaScript API

Предварительные требования

Перед началом работы вам понадобится:

Процесс

  1. Загрузка страницы: скрипт Turnstile загружается и ищет нужные элементы либо ждёт программного вызова.
  2. Рендеринг виджета: виджеты создаются и начинают выполнять проверки.
  3. Генерация токена: после прохождения проверки создаётся токен.
  4. Интеграция с формой: токен передаётся через функции обратного вызова или скрытые поля формы.
  5. Проверка на сервере: ваш сервер получает токен и проверяет его через Siteverify API.

Неявная отрисовка

При неявной отрисовке Turnstile автоматически ищет в вашем HTML элементы с классом cf-turnstile в качестве класса и отрисовывает виджеты без дополнительного кода на JavaScript. Такая настройка идеально подходит для статических страниц, где виджет должен загружаться сразу вместе со страницей.

Сценарии использования

Cloudflare рекомендует применять неявный рендеринг в следующих случаях:

Внедрение

1. Добавьте скрипт Turnstile

Подключение скрипта Turnstile: добавьте Turnstile JavaScript API в HTML-файл внутри <head> или непосредственно перед закрывающим </body> тег.

<script
	src="https://challenges.cloudflare.com/turnstile/v0/api.js"
	async
	defer
></script>

2. (Необязательно) Оптимизируйте производительность с помощью resource hints

Добавьте подсказки ресурсов (resource hints), чтобы браузер заранее устанавливал соединение с серверами Cloudflare и страница загружалась быстрее. Разместите этот <link> в HTML-раздел <head> перед скриптом Turnstile.

<link rel="preconnect" href="https://challenges.cloudflare.com" />

3. Добавьте элементы виджетов

Разместите контейнеры виджетов там, где на сайте должны появляться проверки.

<div class="cf-turnstile" data-sitekey="<YOUR-SITE-KEY>"></div>

4. Настройте с помощью атрибутов data

Настройка виджетов с помощью атрибутов data. Вставьте div в том месте, где должен появиться виджет.

<div
	class="cf-turnstile"
	data-sitekey="<YOUR-SITE-KEY>"
	data-theme="light"
	data-size="normal"
	data-callback="onSuccess"
></div>

После прохождения проверки токен передаётся в обратный вызов success. Этот токен нужно проверить через наш Конечная точка Siteverify.

Полные примеры неявного рендеринга по сценариям

Простая форма входа

Turnstile часто применяют для защиты форм на сайтах, например форм входа или обратной связи. Виджет можно встроить в <form> тег.

Пример
<!DOCTYPE html>
<html>
<head>
    <title>Login Form</title>
    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body>
    <form action="/login" method="POST">
        <input type="text" name="username" placeholder="Username" autocomplete="username" required />
        <input type="password" name="password" placeholder="Password" autocomplete="current-password" required />

        <!-- Turnstile widget with basic configuration -->
        <div class="cf-turnstile" data-sitekey="<YOUR-SITE-KEY>"></div>
        <button type="submit">Log in</button>
    </form>

</body>
</html>

Скрытое поле ввода с именем cf-turnstile-response добавляется и отправляется на сервер вместе с остальными полями.

Полный пример HTML
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>Implicit Rendering with Cloudflare Turnstile</title>
		<script
			src="https://challenges.cloudflare.com/turnstile/v0/api.js"
			async
			defer
		></script>
	</head>
	<body>
		<h1>Contact Us</h1>
		<form action="/submit" method="POST">
			<label for="name">Name:</label><br />
			<input type="text" id="name" name="name" required /><br />
			<label for="email">Email:</label><br />
			<input type="email" id="email" name="email" required /><br />
			<!-- Turnstile Widget -->
			<div class="cf-turnstile" data-sitekey="<YOUR-SITE-KEY>"></div>
			<br />
			<button type="submit">Submit</button>
		</form>
	</body>
</html>

Расширенная форма с обратными вызовами

Пример
<form action="/contact" method="POST" id="contact-form">
	<input type="email" name="email" placeholder="Email" required />
	<textarea name="message" placeholder="Message" required></textarea>
	<!-- Widget with callbacks and custom configuration -->
	<div
		class="cf-turnstile"
		data-sitekey="<YOUR-SITE-KEY>"
		data-theme="auto"
		data-size="flexible"
		data-callback="onTurnstileSuccess"
		data-error-callback="onTurnstileError"
		data-expired-callback="onTurnstileExpired"
	></div>
	<button type="submit" id="submit-btn" disabled>Send Message</button>
</form>

<script>
	function onTurnstileSuccess(token) {
		console.log("Turnstile success:", token);
		document.getElementById("submit-btn").disabled = false;
	}
	function onTurnstileError(errorCode) {
		console.error("Turnstile error:", errorCode);
		document.getElementById("submit-btn").disabled = true;
	}
	function onTurnstileExpired() {
		console.warn("Turnstile token expired");
		document.getElementById("submit-btn").disabled = true;
	}
</script>

Несколько виджетов с разными настройками

Пример
<!-- Compact widget for newsletter signup -->
<form action="/newsletter" method="POST">
	<input type="email" name="email" placeholder="Email" />
	<div
		class="cf-turnstile"
		data-sitekey="<YOUR-SITE-KEY>"
		data-size="compact"
		data-action="newsletter"
	></div>
	<button type="submit">Subscribe</button>
</form>

<!-- Normal widget for contact form -->
<form action="/contact" method="POST">
	<input type="text" name="name" placeholder="Name" />
	<input type="email" name="email" placeholder="Email" />
	<textarea name="message" placeholder="Message"></textarea>
	<div
		class="cf-turnstile"
		data-sitekey="<YOUR-SITE-KEY>"
		data-action="contact"
		data-theme="dark"
	></div>
	<button type="submit">Send</button>
</form>

Автоматическая интеграция с формой

Когда вы встраиваете виджет Turnstile в <form> появится невидимое поле ввода с именем cf-turnstile-response создаётся автоматически. Это поле содержит токен проверки и отправляется вместе с остальными данными формы.

<form action="/submit" method="POST">
	<input type="text" name="data" />
	<div class="cf-turnstile" data-sitekey="<YOUR-SITE-KEY>"></div>
	<!-- Hidden field automatically added: -->
	<!-- <input type="hidden" name="cf-turnstile-response" value="TOKEN_VALUE" /> -->
	<button type="submit">Submit</button>
</form>

Явный рендеринг

Явный рендеринг даёт программный контроль над тем, когда и где появляется виджет и как виджеты создаются с помощью функций JavaScript. Такой способ подходит для динамического контента, одностраничных приложений (SPA) и вывода виджета в зависимости от действий пользователя.

Сценарии использования

Cloudflare рекомендует применять явный рендеринг в следующих случаях:

Внедрение

1. Добавьте скрипт на сайт с явным рендерингом

<script
	src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
	defer
></script>

2. Создайте элементы-контейнеры

Создайте контейнеры без cf-turnstile в качестве класса.

<div id="turnstile-container"></div>

3. Отрисуйте виджеты программно

Вызовите turnstile.render() для создания виджета, когда всё будет готово.

const widgetId = turnstile.render("#turnstile-container", {
	sitekey: "<YOUR-SITE-KEY>",
	callback: function (token) {
		console.log("Success:", token);
	},
});

Необязательные вызовы

После явного рендеринга виджета Turnstile с ним может потребоваться взаимодействие, в зависимости от задач вашего приложения. Управление состоянием виджета описано в разделах ниже.

Сброс виджета

Если виджет истёк по времени или устарел, сбросить его можно функцией:

turnstile.reset(widgetId);

Получение токена ответа

Текущий токен ответа можно получить в любой момент:

const responseToken = turnstile.getResponse(widgetId);

Удаление виджета

Когда виджет больше не нужен, его можно удалить со страницы так:

turnstile.remove(widgetId);

При этом ни один callback не вызывается, а все связанные элементы DOM удаляются.

Полные примеры явного рендеринга по сценариям

Базовая явная реализация

Пример
<!DOCTYPE html>
<html>
	<head>
		<title>Explicit Rendering</title>
		<script
			src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
			defer
		></script>
	</head>
	<body>
		<form id="login-form">
			<input
				type="text"
				name="username"
				placeholder="Username"
				autocomplete="username"
			/>
			<input
				type="password"
				name="password"
				placeholder="Password"
				autocomplete="current-password"
			/>
			<div id="turnstile-widget"></div>
			<button type="submit">Login</button>
		</form>

		<script>
			window.onload = function () {
				turnstile.render("#turnstile-widget", {
					sitekey: "<YOUR-SITE-KEY>",
					callback: function (token) {
						console.log("Turnstile token:", token);
						// Handle successful verification
					},
					"error-callback": function (errorCode) {
						console.error("Turnstile error:", errorCode);
					},
				});
			};
		</script>
	</body>
</html>

Использование обратного вызова onload

Пример
<script
	src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=onTurnstileLoad"
	defer
></script>
<div id="widget-container"></div>
<script>
	function onTurnstileLoad() {
		turnstile.render("#widget-container", {
			sitekey: "<YOUR-SITE-KEY>",
			theme: "light",
			callback: function (token) {
				console.log("Challenge completed:", token);
			},
		});
	}
</script>

Расширенная реализация в SPA

Пример
<div id="dynamic-form-container"></div>

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>

<script>
	class TurnstileManager {
		constructor() {
			this.widgets = new Map();
		}
		createWidget(containerId, config) {
			// Wait for Turnstile to be ready
			turnstile.ready(() => {
				const widgetId = turnstile.render(containerId, {
					sitekey: config.sitekey,
					theme: config.theme || "auto",
					size: config.size || "normal",
					callback: (token) => {
						console.log(`Widget ${widgetId} completed:`, token);
						if (config.onSuccess) config.onSuccess(token, widgetId);
					},
					"error-callback": (error) => {
						console.error(`Widget ${widgetId} error:`, error);
						if (config.onError) config.onError(error, widgetId);
					},
				});

				this.widgets.set(containerId, widgetId);
				return widgetId;
			});
		}
		removeWidget(containerId) {
			const widgetId = this.widgets.get(containerId);
			if (widgetId) {
				turnstile.remove(widgetId);
				this.widgets.delete(containerId);
			}
		}
		resetWidget(containerId) {
			const widgetId = this.widgets.get(containerId);
			if (widgetId) {
				turnstile.reset(widgetId);
			}
		}
	}

	// Usage
	const manager = new TurnstileManager();

	// Create a widget when user clicks a button
	document.getElementById("show-form-btn").addEventListener("click", () => {
		document.getElementById("dynamic-form-container").innerHTML = `
        <form>
            <input type="email" placeholder="Email" />
            <div id="turnstile-widget"></div>
            <button type="submit">Submit</button>
        </form>
    `;
		manager.createWidget("#turnstile-widget", {
			sitekey: "<YOUR-SITE-KEY>",
			theme: "dark",
			onSuccess: (token) => {
				// Handle successful verification
				console.log("Form ready for submission");
			},
		});
	});
</script>

Управление жизненным циклом виджета

Явный рендеринг даёт полный контроль над жизненным циклом виджета.

// Render a widget
const widgetId = turnstile.render("#container", {
	sitekey: "<YOUR-SITE-KEY>",
	callback: handleSuccess,
});

// Get the current token
const token = turnstile.getResponse(widgetId);

// Check if widget is expired
const isExpired = turnstile.isExpired(widgetId);

// Reset the widget (clears current state)
turnstile.reset(widgetId);

// Remove the widget completely
turnstile.remove(widgetId);

Режим выполнения

Режимы выполнения определяют, когда запускаются проверки.

// Render widget but don't run challenge yet
const widgetId = turnstile.render("#container", {
	sitekey: "<YOUR-SITE-KEY>",
	execution: "execute", // Don't auto-execute
});

// Later, run the challenge when needed
turnstile.execute("#container");

Оптимизация производительности и удобства использования

Cloudflare рекомендует запускать скрипт Turnstile как можно раньше при открытии страницы, чтобы к моменту, когда посетитель захочет выполнить на ней какое-либо действие, проверка уже завершилась и виджет был готов к взаимодействию.


Параметры настройки

Неявный и явный способы рендеринга поддерживают одинаковый набор параметров. Наиболее востребованные из них собраны в таблице ниже.

Опция Описание Значения
sitekey Sitekey вашего виджета Обязательная строка
theme Визуальная тема auto, light, dark
size Размер виджета normal, flexible, compact
callback Обработчик успешного выполнения Функция
error-callback Обратный вызов при ошибке Функция
execution Когда запускать проверку render, execute
appearance Когда виджет виден always, execute, interaction-only

Полный список параметров конфигурации приведён в разделе Конфигурации виджетов.


Тестирование

С тестовым sitekey вы можете проверить работу виджета Turnstile на своей веб-странице, не запуская настоящий Cloudflare Challenge.

См. Тестирование, где это описано подробнее.


Ограничения

Turnstile рассчитан на работу только на страницах, которые используют http:// или https:// схемы URI. Другие протоколы, например file://, для встраивания виджета не поддерживаются.


Требования к безопасности