Cloudflare Turnstile — koniec z męczącymi CAPTCHA

24.09.2026 | Autor: Marcin Wiercioch

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.

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"data-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.

Marcin Wiercioch Marcin Wiercioch

programista, full stack developer

Współzałożyciel Okinet, programista PHP, Full stack developer, administrator linux i pasjonat technologii z 20 letnim stażem. Ostatnimi czasy szczególnie rozwijam umiejętności związane z optymalizacją i automatyzacją środowisk developerskich dzięki czemu budowane przez nas aplikacje internetowe są wydajne, bezpieczne i łatwo rozwijalne.

Wszystkie artykuły autora

Udostępnij

Oceń artykuł

Porozmawiaj z nami
o swoim projekcie

+48 506 160 480
biuro@okinet.pl

lub napisz