Turnstile CAPTCHA

Javascript

Head over to the official Turnstile documentation to read more about how to integrate Cloudflare's CAPTCHA solution.

Insert the Turnstile script snippet in your HTML’s <head> element:

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

Configuration

Within your Cloudflare account under Turnstile create a new Site and get the site key and site secret. Set both in your .env file.

.env
TURNSTILE_SITE_KEY=sitekey
TURNSTILE_SECRET_KEY=sitesecret
Alternatively you could use the bnomei.kart.turnstile.sitekey and bnomei.kart.turnstile.secretkey config options. But using the .env file is safer.

Widget

Render the Turnstile widget with the code from the documentation or use the following snippet kart/turnstile-widget.

<?php snippet('kart/turnstile-widget') ?>

Securing Forms

It might suffice to only secure routes accessible before the user is logged in, like the Login- and Register/Sign-Up-Forms. That is assuming bots do not create valid logins.

Use the code from the documentation or the following snippet kart/turnstile-form.

<form action="<?= kart()->urls()->magiclink() ?>" method="POST">
    <label>
        <input type="email" name="email" required
                  placeholder="<?= t('email') ?>" autocomplete="email"
                  value="<?= urldecode(get('email', '')) ?>">
    </label>
    <?php snippet('kart/turnstile-form') ?>
    <input type="hidden" name="redirect" value="<?= url('kart/login') ?>?status=sent">
    <input type="hidden" name="success_url" value="<?= url('kart') ?>?msg=Welcome%20back">
    <button type="submit"><?= t('login') ?> <?= t('link') ?></button>
</form>

Behind the Scenes

The endpoints intended for public use, which are most likely targeted by bots (login, register/signup, magic-link), are preconfigured with a check for the Turnstile token.

If posted with the form the \Bnomei\Kart\Router::denied()-helper will query the https://challenges.cloudflare.com/turnstile/v0/siteverify endpoint with your secretkey and check if the form request is legit or not.

On success, the form will continue as intended. If not, it will redirect to the error page or yield a 401 HTTP status code.

Kirby Kart is not affiliated with the developers of Kirby CMS. We are merely standing on the shoulder of giants.
© 2025 Bruno Meilick All rights reserved.