Zaznacz wszystkie pola z sygnalizacją świetlną. Teraz z rowerami. Teraz jeszcze raz, bo kliknąłeś o piksel za daleko. Każdy zna ten rytuał — i każdy właściciel strony powinien wiedzieć, że każde takie ćwiczenie to porzucone formularze i utracone zapytania ofertowe. W ostatnim artykule naszej serii o narzędziach Cloudflare bierzemy na warsztat Turnstile — darmową alternatywę dla reCAPTCHA, która odróżnia ludzi od botów bez zagadek obrazkowych. Pokażemy pełne wdrożenie: od widgetu w HTML po weryfikację po stronie PHP, którą łatwo wpiąć w formularze WordPressa.
Cloudflare Turnstile — koniec z męczącymi CAPTCHA
24.09.2026 | Autor: Marcin Wiercioch
Co jest nie tak z klasyczną CAPTCHA?
- UX i konwersja — badania od lat pokazują to samo: dodatkowa łamigłówka w formularzu to kilka-kilkanaście procent porzuceń więcej; na urządzeniach mobilnych bywa gorzej,
- dostępność — zagadki obrazkowe wykluczają osób słabowidzące, a alternatywy dźwiękowe bywają trudniejsze niż sam test,
- prywatność — reCAPTCHA przesyła dane o użytkowniku do Google, co w świetle RODO wymaga zgody i rzetelnej informacji; europejskie organy ochrony danych przyglądały się temu wielokrotnie,
- skuteczność — nowoczesne boty rozwiązują zagadki obrazkowe często lepiej niż ludzie, więc cierpi głównie człowiek.
Jak działa Turnstile?
Turnstile zamiast zagadek uruchamia w tle zestaw nieinwazyjnych testów przeglądarki — sprawdza cechy środowiska i zachowania charakterystyczne dla botów, bez profilowania użytkownika i bez cookies śledzących. Użytkownik widzi najwyżej mały widget z kręcącym się wskaźnikiem i znaczkiem sukcesu. Wynik weryfikacji trafia do formularza jako token, który Twój serwer musi potwierdzić w API Cloudflare. Usługa jest darmowa, działa też na stronach, które nie korzystają z Cloudflare jako CDN, i występuje w trzech trybach: zarządzanym (widget), nieinteraktywnym (pasek bez udziału użytkownika) oraz niewidzialnym.
Krok 1: klucze
W panelu Cloudflare (sekcja Turnstile) dodajemy widget dla swojej domeny i dostajemy parę kluczy: site key (publiczny, trafia do HTML) i secret key (tajny, zostaje na serwerze). Do testów lokalnych Cloudflare udostępnia specjalne klucze testowe, które zawsze przechodzą albo zawsze odrzucają — wygodne w środowisku deweloperskim.
Krok 2: widget w formularzu
<form action="/wyslij.php" method="POST">
<input type="text" name="name" required>
<input type="email" name="email" required>
<textarea name="message" required></textarea>
<div class="cf-turnstile"
data-sitekey="0x4AAAAAAA_TwojSiteKey"
data-theme="auto"
data-language="pl"></div>
<button type="submit">Wyślij</button>
</form>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
Po pomyślnej weryfikacji Turnstile sam dodaje do formularza ukryte pole cf-turnstile-response z tokenem. I tu ważna rzecz, którą widać w połowie wdrożeń, jakie przejmujemy: sama obecność widgetu niczego nie chroni. Bot może wysłać POST bezpośrednio, z pominięciem przeglądarki. Ochrona powstaje dopiero w kroku trzecim.
Krok 3: weryfikacja po stronie serwera
Serwer musi wysłać token do endpointu siteverify i sprawdzić odpowiedź. W PHP — a więc i w WordPressie — wygląda to tak:
function turnstile_ok(string $token, string $ip): bool {
if ($token === "") {
return false;
}
$response = wp_remote_post("https://challenges.cloudflare.com/turnstile/v0/siteverify", [
"body" => [
"secret" => TURNSTILE_SECRET_KEY,
"response" => $token,
"remoteip" => $ip,
],
"timeout" => 5,
]);
if (is_wp_error($response)) {
return false;
}
$data = json_decode(wp_remote_retrieve_body($response), true);
return !empty($data["success"]);
}
// w obsłudze formularza:
$token = $_POST["cf-turnstile-response"] ?? "";
if (!turnstile_ok($token, $_SERVER["REMOTE_ADDR"])) {
wp_die("Weryfikacja antyspamowa nie powiodła się. Spróbuj ponownie.");
}
Sekret trzymamy w wp-config.php (stała TURNSTILE_SECRET_KEY), nie w kodzie motywu. Ważne szczegóły protokołu: token jest jednorazowy i ważny 300 sekund — nie da się go zweryfikować dwa razy, więc przy własnych walidacjach AJAX trzeba po nieudanej próbie zresetować widget (turnstile.reset()).
Integracja z wtyczkami WordPressa
Jeśli formularze obsługuje Contact Form 7, WPForms, Gravity Forms czy WooCommerce, nie trzeba pisać kodu — dojrzałe wtyczki (np. Simple Cloudflare Turnstile) dodają widget i weryfikację do formularzy logowania, rejestracji, komentarzy i checkoutu po wklejeniu pary kluczy. Własny kod, jak wyżej, zostawiamy na formularze autorskie — choćby taki jak nasz formularz kontaktowy.
Tryby pracy i dobre praktyki
- zacznij od trybu zarządzanego (Managed) — Cloudflare sam decyduje, kiedy pokazać interakcję; tryb niewidzialny zostaw formularzom o niskim ryzyku,
- ustaw
data-theme="auto"idata-language="pl"— widget dopasuje się do motywu strony i języka użytkownika, - Turnstile chroni formularz, nie całą stronę — masowe boty skanujące witrynę zatrzymuje dopiero WAF/rate limiting na poziomie Cloudflare,
- zostaw sobie logi odrzuconych weryfikacji (kody błędów z siteverify) — ułatwiają diagnostykę, gdy klient zgłosi, że „formularz nie działa”,
- pamiętaj o poprawnym CSP: skrypt i ramki Turnstile potrzebują wyjątku dla domeny challenges.cloudflare.com.
Turnstile a RODO
Turnstile nie używa cookies do śledzenia i nie buduje profilu użytkownika, a Cloudflare występuje tu jako procesor danych — w praktyce wdrożenie sprowadza się do wzmianki w polityce prywatności, bez odrębnej zgody blokującej formularz. To zupełnie inny ciężar prawny niż osadzanie usługi, która łączy weryfikację z ekosystemem reklamowym.
Podsumowanie serii
To już piąty i ostatni odcinek naszego cyklu: przeszliśmy od uruchamiania kodu na krawędzi sieci (Workers), przez magazyny danych (KV i R2) i analitykę produktową (PostHog), aż po ochronę formularzy bez irytowania ludzi. Wspólny mianownik? Każde z tych narzędzi pozwala małym zespołom korzystać z infrastruktury, która jeszcze dekadę temu wymagała działu DevOps. Jeśli chcesz przenieść któreś z tych rozwiązań do swojego projektu — od pojedynczego formularza po pełną architekturę na edge’u — porozmawiajmy.



