Введение: что вы получите от этого гайда

Cloudflare Turnstile — это тот самый небольшой виджет с крутящимся кружком и надписью «Verifying», который всё чаще встречается вместо привычной капчи с картинками. Он стоит на формах регистрации, в корзинах интернет-магазинов, на лендингах и в личных кабинетах сервисов. Обычный посетитель его почти не замечает. А вот для маркетолога, арбитражника или разработчика, который работает через мобильные прокси и открывает десятки сайтов в день, он превращается в загадку. Почему на одном профиле проверка пролетает за секунду, а на другом виджет задумывается, просит поставить галочку или выдаёт код ошибки?

В этом гайде мы разберём Cloudflare Turnstile с двух сторон. Со стороны владельца сайта — вы своими руками подключите виджет на страницу, настроите серверную проверку и научитесь читать статистику. Со стороны посетителя — вы поймёте, какие именно сигналы собирает Turnstile, что он видит о вашем браузере, сети и прокси, и почему принимает то или иное решение. Это знание одинаково полезно и тем, кто защищает свои формы от ботов, и тем, кто хочет, чтобы его рабочие профили выглядели для проверки как обычные пользователи.

Для кого этот гайд

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

Что нужно знать заранее

Специальных знаний не требуется. Достаточно понимать, что такое HTML-страница, уметь открыть консоль разработчика в браузере и иметь хотя бы минимальный опыт работы с любым языком на сервере — PHP, Node.js, Python. Если серверной части у вас нет, вы всё равно пройдёте большую часть гайда: виджет можно подключить и протестировать на локальной странице.

Сколько времени потребуется

Полное прохождение — около полутора-двух часов. Регистрация и создание виджета занимают 10-15 минут, встраивание на страницу — 20 минут, серверная проверка — 30-40 минут, тестирование и диагностика — ещё 30 минут. Теоретические разделы можно читать в любом порядке и возвращаться к ним по мере необходимости.

Предварительная подготовка: инструменты и доступы

Прежде чем начинать, соберите всё необходимое. Это избавит вас от пауз в середине процесса.

Необходимые инструменты и доступы

  • Аккаунт Cloudflare. Бесплатный. Регистрируется по адресу электронной почты за пару минут. Домен на Cloudflare переносить не обязательно — Turnstile работает на любом сайте, где бы он ни хостился.
  • Сайт или тестовая страница. Подойдёт любая HTML-страница с формой. Для локальных экспериментов достаточно файла на компьютере, открытого через простой локальный сервер.
  • Серверная среда. Любой хостинг с PHP, либо Node.js или Python на вашей машине. Нужна для второй половины гайда — проверки токена.
  • Современный браузер. Chrome, Firefox, Edge или Safari актуальной версии с открытыми инструментами разработчика.
  • Мобильный прокси с возможностью смены IP. Понадобится в диагностическом разделе, чтобы посмотреть, как виджет реагирует на разные сети и ротацию адресов.

Системные требования

Turnstile не требовательный. Виджет работает в любом браузере, который поддерживает современный JavaScript, и загружает свой код с домена challenges.cloudflare.com. Если в вашей сети или в расширениях браузера этот домен заблокирован, виджет не загрузится — учитывайте это при тестировании. Для серверной проверки требуется возможность делать исходящие HTTPS-запросы.

Что подготовить перед началом

  1. Заведите текстовый файл для заметок. В него вы будете записывать site key, название виджета, список хостнеймов и результаты тестов.
  2. Откройте страницу с формой, которую хотите защитить, и сохраните её копию с пометкой даты. Это ваша резервная копия.
  3. Если у вас есть серверный обработчик формы, сделайте копию и его тоже. Мы будем добавлять в него код проверки.
  4. Проверьте, что ваш локальный или боевой сервер отдаёт страницу по HTTPS или через localhost. Turnstile работает и по обычному HTTP, но на боевом сайте вам всё равно нужен HTTPS.

⚠️ Внимание: Секретный ключ виджета нельзя хранить в HTML, в JavaScript на странице или в публичном репозитории. Он живёт только на сервере. Если вы случайно опубликовали его, сразу перевыпустите ключ в панели Cloudflare — старый перестанет работать.

Базовые понятия: как устроен Cloudflare Turnstile

Чтобы дальнейшие шаги были понятными, разберём ключевые термины простым языком.

Ключевые термины

  • Виджет — тот блок, который видит посетитель. Технически это iframe, загруженный с домена Cloudflare и встроенный в вашу страницу.
  • Site key — публичный идентификатор виджета. Он вставляется в HTML и виден всем. По нему Cloudflare понимает, какой виджет отрисовать и для каких доменов он разрешён.
  • Secret key — приватный ключ. Им ваш сервер подтверждает, что пришедший токен настоящий. Никогда не покидает сервер.
  • Токен — строка, которую виджет выдаёт после успешной проверки. Она кладётся в скрытое поле формы и уходит на ваш сервер вместе с остальными данными.
  • Siteverify — эндпоинт Cloudflare, куда сервер отправляет токен вместе с секретным ключом и получает ответ: успех или нет.
  • Режим виджета — способ показа: управляемый (Managed), неинтерактивный (Non-interactive) или невидимый (Invisible). Разница описана ниже.
  • Хостнейм — домен, на котором разрешено использовать виджет. Если домен не указан, виджет откажется работать с ошибкой.

Принцип работы в четырёх фразах

  1. Страница загружает скрипт Turnstile, и виджет тихо запускает в браузере набор проверок.
  2. Cloudflare собирает результаты, оценивает их вместе с данными о сети и решает: пропустить сразу, показать галочку для подтверждения или отказать.
  3. При успехе виджет генерирует одноразовый токен и подставляет его в форму.
  4. Ваш сервер получает форму, отправляет токен на siteverify и только при положительном ответе обрабатывает заявку.

Что Turnstile проверяет — общая картина

Здесь важно понимать главное. Cloudflare Turnstile не смотрит на «человечность» через головоломки с картинками. Он оценивает согласованность окружения: насколько браузер, сеть и поведение сходятся в одну правдоподобную картину. Основные группы сигналов:

  • Окружение браузера. Скрипт выполняет серию небольших JavaScript-задач и проверяет, что среда ведёт себя как настоящий браузер: как устроены объекты окна, как рендерится графика, есть ли признаки автоматизации, совпадает ли заявленный User-Agent с реальными возможностями движка.
  • Доказательство работы. Виджет просит браузер выполнить небольшое вычисление. Для человека это доли секунды, для бота, который открывает тысячи страниц, — ощутимая нагрузка.
  • Сетевые сигналы. Репутация IP-адреса и автономной системы, из которой идёт запрос, соответствие сетевых характеристик заявленному браузеру, история запросов с этого адреса по всей сети Cloudflare.
  • Токены доверия устройства. На устройствах Apple и в некоторых других экосистемах Turnstile может запросить у операционной системы подтверждение, что перед ним настоящее устройство, — и тогда проверка проходит вообще без вычислений.
  • Поведение на странице. Время появления виджета, момент отправки формы, естественность действий в управляемом режиме.

Что Turnstile не делает: не собирает данные для рекламного профилирования, не отслеживает пользователя между сайтами через сторонние cookie и никогда не показывает пазлы с картинками. Это важно и с точки зрения закона о персональных данных, и с точки зрения конверсии — посетители не уходят из-за раздражающей капчи.

Три режима виджета

  • Managed — режим по умолчанию. Виджет виден, крутит индикатор, и если сомневается, показывает галочку, которую нужно нажать. Подходит для большинства форм.
  • Non-interactive — виджет виден, но никогда не требует действий. Либо проходит сам, либо выдаёт ошибку. Хорош для страниц, где нельзя допустить лишних кликов.
  • Invisible — виджет вообще не отрисовывается. Проверка идёт в фоне. Удобен для кнопок и форм, где вы не хотите менять дизайн, но требует аккуратной обработки ошибок.

Шаг 1: Разбираемся, что именно Turnstile видит с вашей стороны

Цель этапа: перед тем как что-то настраивать, вы должны понимать, какие данные о вашем окружении получает виджет. Это база для диагностики на следующих шагах и для осознанной работы через мобильные прокси.

Как посмотреть работу виджета своими глазами

  1. Откройте любой сайт, где стоит Cloudflare Turnstile. Такие виджеты легко узнать по логотипу Cloudflare в правом нижнем углу блока и ссылкам «Privacy» и «Terms».
  2. Нажмите F12 или правой кнопкой мыши — «Просмотреть код», чтобы открыть инструменты разработчика.
  3. Перейдите на вкладку «Network» (Сеть) и обновите страницу.
  4. В строке фильтра введите challenges.cloudflare.com. Вы увидите несколько запросов: загрузку api.js, загрузку самого iframe виджета и один или несколько POST-запросов — это и есть отправка результатов проверок.
  5. Откройте вкладку «Elements» (Элементы) и найдите блок с классом cf-turnstile. Внутри него после успешной проверки появится скрытое поле input с именем cf-turnstile-response и длинной строкой в значении. Это токен.

Совет: Содержимое POST-запросов зашифровано и обфусцировано, читать его бесполезно. Смотрите на другое: сколько запросов ушло, сколько времени заняла проверка и сменился ли статус виджета на «Success». Это и есть ваш внешний индикатор доверия.

Что Turnstile видит о вашем браузере

Виджет выполняет JavaScript прямо в вашем окне, поэтому ему доступно всё, что доступно любому скрипту на странице: версия движка, установленные API, размеры экрана, часовой пояс, языки интерфейса, особенности рендеринга графики и шрифтов, поведение функций, которые в автоматизированных браузерах часто переопределены. Он не читает ваши файлы и не лезет в другие вкладки. Но он отлично замечает, когда браузер заявляет одно, а делает другое. Например, User-Agent говорит «Chrome на Android», а в окружении нет сенсорных событий и есть API, которых на мобильных устройствах не бывает.

Что Turnstile видит о вашей сети

Здесь начинается самое интересное для тех, кто работает через мобильные прокси. Все запросы виджета идут на серверы Cloudflare, а значит, Cloudflare видит ваш внешний IP-адрес, его автономную систему (то есть оператора), страну, а также низкоуровневые характеристики соединения — как именно ваш клиент устанавливает защищённое соединение. Эти характеристики у разных браузеров разные, и Cloudflare сравнивает их с заявленным User-Agent.

Мобильные операторы выдают адреса из больших общих пулов, за одним адресом одновременно сидят сотни реальных абонентов. Поэтому такие адреса сами по себе имеют нейтральную или хорошую репутацию — заблокировать их означало бы заблокировать реальных людей. Но репутация — только один из сигналов. Если с мобильного адреса приходит браузер, у которого сетевой отпечаток настольного скрипта, часовой пояс другого континента и признаки автоматизации, картина перестаёт сходиться, и виджет переключается в интерактивный режим или отказывает.

Что Turnstile видит о вашем поведении

В управляемом режиме виджет обращает внимание на то, как быстро форма отправляется после загрузки, взаимодействовал ли пользователь со страницей, естественно ли выглядит клик по галочке. В невидимом и неинтерактивном режимах поведенческий компонент минимален — решение принимается по окружению и сети.

✅ Проверка: На этом этапе вы должны уметь открыть вкладку Network, отфильтровать запросы к challenges.cloudflare.com, увидеть скрытое поле cf-turnstile-response и объяснить своими словами три группы сигналов: браузер, сеть, поведение. Если это получилось — переходите к созданию своего виджета.

Возможные проблемы

  • Запросов к challenges.cloudflare.com нет вообще. Скорее всего, домен блокируется расширением браузера или корпоративным фильтром. Отключите блокировщики на время тестов.
  • Виджет висит в состоянии проверки бесконечно. Проверьте системное время на компьютере: сильное расхождение с реальным временем ломает проверку.

Шаг 2: Создаём виджет в панели Cloudflare

Цель этапа: получить пару ключей — site key и secret key — и правильно настроить список доменов и режим работы.

  1. Откройте панель управления Cloudflare и войдите в аккаунт. Если аккаунта нет — нажмите «Sign up», введите почту и пароль, подтвердите письмо.
  2. В левом меню найдите пункт Turnstile. Если у вас несколько аккаунтов, сначала выберите нужный на главной странице.
  3. Нажмите синюю кнопку Add widget (Добавить виджет).
  4. В поле Widget name введите понятное название, например «Лендинг заявки — основной». Название видно только вам, но при десятке виджетов оно спасёт от путаницы.
  5. В блоке Hostname management нажмите Add hostnames и введите домены, на которых будет работать виджет. Вводите без протокола и без пути: example.ru, а не https://example.ru/form. Поддомены нужно добавлять отдельно или указывать корневой домен — тогда поддомены тоже будут разрешены.
  6. Для локальных тестов добавьте в список localhost. Это официально поддерживается и не мешает боевой работе.
  7. В блоке Widget Mode выберите режим. Для первого раза берите Managed — так вы увидите все состояния виджета, включая интерактивное.
  8. Опцию Pre-clearance пока оставьте выключенной. Она нужна, только если сайт проксируется через Cloudflare, и о ней мы поговорим в продвинутом разделе.
  9. Нажмите Create.
  10. На следующем экране вы увидите два поля: Site Key и Secret Key. Скопируйте оба в файл заметок. Секретный ключ можно посмотреть позже в настройках виджета, но удобнее сохранить сразу.

Совет: Создайте сразу два виджета — один для боевого домена, второй с именем «Тест» и хостнеймом localhost. Так вы будете экспериментировать с режимами и настройками, не трогая статистику рабочего виджета.

Как выглядит правильный результат

В списке Turnstile появится карточка с названием виджета, его режимом и списком хостнеймов. Site key начинается с «0x» и имеет длину около 24 символов, secret key — тоже с «0x», но длиннее. Если ключ выглядит иначе, вы, скорее всего, скопировали не то поле.

✅ Проверка: В вашем файле заметок записаны site key, secret key, название виджета, список хостнеймов и выбранный режим. В панели Cloudflare виджет отображается в списке со статусом активного.

Возможные проблемы

  • Кнопка Create неактивна. Не добавлен ни один хостнейм или введён с ошибкой (протокол, слэш, пробел).
  • Не находится пункт Turnstile в меню. Вы находитесь внутри настроек конкретного домена. Вернитесь на уровень аккаунта — Turnstile живёт там, а не внутри зоны.

Шаг 3: Встраиваем виджет на страницу с формой

Цель этапа: виджет отображается на вашей странице, проходит проверку и подставляет токен в форму.

Подключаем скрипт

  1. Откройте HTML-файл страницы с формой в редакторе.
  2. Внутри тега head или перед закрывающим тегом body добавьте строку подключения скрипта:
<script src='https://challenges.cloudflare.com/turnstile/v0/api.js' async defer></script>

Атрибуты async и defer позволяют странице не ждать загрузки скрипта. Виджет появится чуть позже, но пользователь не увидит задержки в загрузке контента.

Размещаем контейнер виджета

  1. Найдите форму, которую защищаете. Обычно это тег form с полями имени, почты, телефона.
  2. Прямо перед кнопкой отправки вставьте пустой блок с классом cf-turnstile и вашим site key:
<form action='/submit.php' method='POST'> <input type='text' name='name' placeholder='Ваше имя'> <input type='email' name='email' placeholder='Почта'> <div class='cf-turnstile' data-sitekey='ВАШ_SITE_KEY' data-theme='light'></div> <button type='submit'>Отправить</button> </form>
  1. Замените ВАШ_SITE_KEY на ключ из файла заметок. Секретный ключ сюда вставлять нельзя.
  2. Сохраните файл и откройте страницу в браузере через localhost.

Что вы должны увидеть

Через одну-две секунды после загрузки в месте блока появится виджет размером примерно 300 на 65 пикселей. Сначала он показывает индикатор загрузки и текст «Verifying», затем — зелёную галочку и «Success». Если Cloudflare решил перепроверить окружение, появится чекбокс с текстом «Verify you are human» — нажмите его, и через мгновение виджет покажет успех.

Откройте инструменты разработчика, вкладку Elements, и разверните блок cf-turnstile. Внутри появилось скрытое поле input с именем cf-turnstile-response. Его значение — длинный токен. Именно он уйдёт на сервер при отправке формы.

Полезные атрибуты контейнера

  • data-theme — light, dark или auto. Auto подстраивается под системную тему пользователя.
  • data-size — normal, compact или flexible. Flexible растягивает виджет по ширине контейнера — удобно для мобильной вёрстки.
  • data-language — код языка, например ru. По умолчанию виджет берёт язык браузера.
  • data-action — короткая метка, например login или checkout. Она вернётся в ответе siteverify и поможет отличать формы в статистике.
  • data-callback — имя JavaScript-функции, которая вызовется после успеха. В неё придёт токен.
  • data-error-callback — функция, которая получит код ошибки, если что-то пошло не так.
  • data-refresh-expired — что делать, когда токен устарел: auto перезапрашивает сам, manual показывает кнопку обновления, never ничего не делает.

Совет: Сразу добавьте data-error-callback и выводите код ошибки в консоль. Коды Turnstile информативны: серия 110xxx говорит о проблемах с ключом или доменом, 300xxx — о сбое выполнения в браузере, 600xxx — о том, что проверка не пройдена. Без этого вы будете гадать, почему виджет молчит.

Альтернативный путь: явный рендер через JavaScript

Если вы работаете во фреймворке или хотите контролировать момент появления виджета, замените неявный рендер на явный. Добавьте к адресу скрипта параметр render=explicit и вызовите turnstile.render с нужными параметрами:

turnstile.render('#my-widget', { sitekey: 'ВАШ_SITE_KEY', theme: 'auto', action: 'signup', callback: function(token) { console.log('Токен получен', token.length); } });

Такой способ позволяет перерисовать виджет после ошибки методом turnstile.reset и получить текущий токен методом turnstile.getResponse.

✅ Проверка: Виджет отображается на странице, показывает «Success», в DOM присутствует поле cf-turnstile-response с токеном, в консоли нет ошибок. Попробуйте обновить страницу три-четыре раза — каждый раз должен появляться новый токен.

Возможные проблемы

  • Виджет показывает ошибку 110200. Домен, с которого открыта страница, не добавлен в хостнеймы виджета. Проверьте, что открываете именно через localhost, а не через 127.0.0.1 или file:// — это разные хостнеймы.
  • Виджет не появляется, в консоли пусто. Скрипт не загрузился. Проверьте адрес скрипта на опечатки и отсутствие блокировщиков.
  • Виджет ломает вёрстку. Используйте data-size='flexible' или оберните блок в контейнер нужной ширины.

Шаг 4: Настраиваем серверную проверку токена

Цель этапа: сервер отклоняет любые отправки формы без действующего токена. Это самый важный шаг — без него виджет остаётся просто украшением, потому что бот может отправить POST-запрос напрямую, минуя страницу.

Как устроен запрос к siteverify

Ваш сервер отправляет POST-запрос по адресу https://challenges.cloudflare.com/turnstile/v0/siteverify с полями:

  • secret — ваш секретный ключ;
  • response — токен из поля cf-turnstile-response;
  • remoteip — IP посетителя, необязательно, но полезно;
  • idempotency_key — необязательный уникальный идентификатор запроса, о нём в продвинутом разделе.

В ответ приходит JSON. Ключевые поля:

{ "success": true, "challenge_ts": "2026-03-14T10:22:31.000Z", "hostname": "example.ru", "error-codes": [], "action": "signup", "cdata": "" }

Токен живёт 300 секунд и является одноразовым. Повторная проверка того же токена вернёт ошибку timeout-or-duplicate.

Пример на PHP

  1. Откройте файл-обработчик формы, например submit.php.
  2. В самом начале, до любой работы с данными формы, добавьте блок проверки:
<?php $token = $_POST['cf-turnstile-response'] ?? ''; if ($token === '') { http_response_code(400); exit('Проверка не пройдена: нет токена'); } $data = [ 'secret' => getenv('TURNSTILE_SECRET'), 'response' => $token, 'remoteip' => $_SERVER['REMOTE_ADDR'] ]; $ch = curl_init('https://challenges.cloudflare.com/turnstile/v0/siteverify'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $raw = curl_exec($ch); curl_close($ch); $result = json_decode($raw, true); if (empty($result['success'])) { http_response_code(403); exit('Проверка не пройдена: ' . implode(',', $result['error-codes'] ?? ['no-response'])); } 

Об авторе

Роман Мельников

Роман Мельников

Технический писатель и системный администратор

Опыт работы: Технический писатель и DevOps-инженер с 9-летним опытом. Создал более 50 подробных гайдов по настройке и администрированию систем. Его инструкции помогли тысячам специалистов успешно решить технические задачи. Популярный автор на Habr и YouTube.
Образование: Московский государственный технический университет имени Н.Э. Баумана. Информационные системы и технологии
Экспертиза:
Техническая документация DevOps Системное администрирование Linux Docker и Kubernetes CI/CD Автоматизация инфраструктуры Облачные технологии Мониторинг систем Bash и Python скриптинг

Поделитесь статьёй: