Cloudflare Turnstile CAPTCHA Checkbox with PHP
Cloudflare's Turnstile is a modern alternative to other traditional CAPTCHA systems and providers. It helps to balance a website's security without disturbing the user experience. Learn how to implement Cloudflare Turnstile checkbox CAPTCHA in PHP with minimal effort.

Cloudflare Turnstile is a new human verification tool that serves as an alternative to other CAPTCHA systems. It aims to provide bot protection without complex challenges like other traditional CAPTCHA systems. This post demonstrates how to add Cloudflare Turnstile CAPTCHA in PHP in a simple and easy way. To implement Cloudflare Turnstile, we are going to create these files:
- index.php: Contains the HTML content with the Cloudflare checkbox.
- verify-turnstile.php: The server-side script to verify Turnstile response.
- javascript.js: A JavaScript file that prevents form submission if the turnstile response is not ready.
- style.css: CSS Stylesheet for the page.
Cloudflare's Turnstile CAPTCHA is easy to implement and requires less effort. It does not require user tracking with cookies. It provides a better user experience than other CAPTCHA services. In short, it provides bot protection without privacy concerns with a better user experience.
How to Integrate Cloudflare Turnstile CAPTCHA in PHP - (Step-by-Step)
Integrating Cloudflare Turnstile CAPTCHA to a website involves a few simple steps. We need a cloudflare account and create a Turnstile widget in cloudflare. Getting keys and adding CAPTCHA to the HTML user interface. To implement cloudflare CAPTCHA, follow these steps:
Step 1: Create a Turnstile Widget in Cloudflare
In order to implement cloudflare CAPTCHA, we need to create a Turnstile widget in the cloudflare account. Follow the steps below to create a Turnstile Widget:
- Log in to the cloudflare account dashboard.
- In the left side navigation menu, click "Turnstile".
- Click on the "+ Add Widget" button on the Turnstile widget page.
- Enter a widget name of your choice.
- Click on "+ Add Hostnames".
- Add the hostnames you want to allow to use this widget.
- In the "Widget Mode" section, keep the "Managed" option checked.
- Click on "Create".

Step 2: Get Turnstile Site Key and Secret Key
After the widget has been created by following the above steps. A page with Site Key and Secret Key will be displayed. Copy both and store them in a constants file.
Step 3: Create Turnstile Configuration Constants File
Create a PHP file constants.php, to store Turnstile challenges URL, site key and secret key.
constants.php
<?php
define('TURNSTILE_CHALLENGES_URL', 'https://challenges.cloudflare.com/turnstile/v0');
define('TURNSTILE_SITE_KEY', 'YOUR_TURNSTILE_SITE_KEY');
define('TURNSTILE_SECRET_KEY', 'YOUR_TURNSTILE_SECRET_KEY');
Step 4: Add Cloudflare Turnstile CAPTCHA Checkbox to HTML Form
Next, we need a user interface where the turnstile captcha will be displayed for human verification. Create a web page with HTML content and a form, load the turnstile challenges script and add a turnstile CAPTCHA container.
index.php
<?php include_once 'constants.php'; ?>
<!DOCTYPE html>
<html>
<head>
<title>Cloudflare Turnstile CAPTCHA Checkbox with PHP - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"/>
<link rel="stylesheet" href="css/style.css"/>
<script src="<?= TURNSTILE_CHALLENGES_URL; ?>/api.js" defer></script>
<script src="js/javascript.js" type="text/javascript"></script>
</head>
<body>
<section class="section py-4">
<div class="container">
<form action="verify-turnstile.php" method="POST" class="turnstile-form mb-4">
<div class="mb-4">
<div class="cf-turnstile"
data-sitekey="<?= TURNSTILE_SITE_KEY; ?>"
data-size="flexible"
data-response-field-name="cf_turnstile_response"></div>
</div>
<div class="mb-4">
<button type="submit" class="btn btn-blue">Send</button>
</div>
</form>
</div>
</section>
</body>
</html>
Step 5: Prevent Form Submissions without Human Verification
We need to make the CAPTCHA checkbox a required field, so users cannot submit the form without human verification. It can be achieved by adding JavaScript to prevent form submission and show an alert if a user has not verified the Turnstile checkbox.
javascript.js
document.addEventListener("DOMContentLoaded", function () {
document.querySelector(".turnstile-form")
.addEventListener("submit", function (e) {
let turnstile_response = document.querySelector('input[name="cf_turnstile_response"]');
if (!turnstile_response || !turnstile_response.value) {
e.preventDefault(); // Stop form submission
alert("Cloudflare CAPTCHA is required.");
}
});
});Step 6: Verify Turnstile Response on Server-Side
Now, after integrating the turnstile CAPTCHA into the HTML form, we still need to verify it on the server side after form submission. Create a PHP file to handle form submission and verify the turnstile response submitted with the form. Steps to verify the turnstile CAPTCHA response are:
- Include the constants file to use them on page.
- Sanitize the input
$_POSTarray. - Create a new cURL instance.
- Add the challenges API endpoint as a cURL option.
- Pass the Secret Key as a
secretparameter in the data of cURL request and the turnstileresponsesubmitted with the form for verification. - Execute a cURL request and close the cURL session.
- Decode the API response with the
json_decode()function. - Check if the response was not successful, then redirect the user back to the same page. You can add an error message in the session here.
- If the response was successful, process the form.
verify-turnstile.php
<?php
include_once 'constants.php';
$post = filter_input_array(INPUT_POST);
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, TURNSTILE_CHALLENGES_URL . '/siteverify');
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_handle, CURLOPT_POST, true);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, http_build_query([
'secret' => TURNSTILE_SECRET_KEY,
'response' => $post['cf_turnstile_response'],
]));
$response = curl_exec($curl_handle);
curl_close($curl_handle);
// Decode the JSON response
$response_data = json_decode($response, true);
// If Turnstile response was not successful, redirect user with error message here
if (!$response_data['success']) {
header('Location: ' . filter_var($_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL));
}
// Everything worked fine, Process your form here
Step 7: Add Turnstile CAPTCHA Interface CSS Styles
Add CSS styles for the entire turnstile checkbox user interface page and turnstile checkbox container as well.
style.css
* {
box-sizing: border-box;
}
html,body {
margin: 0;
padding: 0;
}
body {
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
}
.container {
max-width: 1024px;
margin: 0 auto;
padding-left: 15px;
padding-right: 15px;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.my-1, .mb-1 {
margin-bottom: .25rem;
}
.my-4, .mb-4 {
margin-bottom: 1rem;
}
.btn {
display: inline-block;
padding: .375rem .75rem;
cursor: pointer;
font-size: inherit;
}
.btn-blue {
background-color: #0369a1;
border: 1px solid #0369a1;
color: #ffffff;
}
.btn-blue:hover {
background-color: #005D95;
}
.cf-turnstile{
min-height: 65px;
}With these code snippets, we implemented Cloudflare's Turnstile Captcha Checkbox for bot protection. Do have a look at the Turnstile product page for pricing and the features it provides.