CAPTCHA systems are essential for protecting web forms from automated abuse. Many developers rely on prebuilt plugins or third-party packages, but manually integrating CAPTCHA provides greater control and flexibility. By managing both the client-side widget and server-side verification directly, developers can ensure the CAPTCHA functions exactly as needed and integrates cleanly with any application framework.
In this article, we walk through manual integration of Cloudflare Turnstile and hCaptcha, starting with a framework-agnostic approach suitable for any web application, and then demonstrating how to implement the same functionality in WordPress, using the platform’s hooks and APIs. Each section explains how the code works and how to adapt it for your own application.
The article covers manual integration of Cloudflare Turnstile and hCaptcha for any web application, and also includes implementation in WordPress, which involves editing functions.php and using the platform’s hooks and APIs.
CAPTCHA Implementation
Cloudflare Turnstile
Cloudflare Turnstile is designed to be light, privacy-focused, and invisible to most users. The first step is to load the Turnstile JavaScript library with explicit rendering. Explicit rendering allows you to control exactly where the CAPTCHA appears and when it is initialized.
Below is an example showing how to add Turnstile to a simple HTML form. In this form, users enter a username and password. Before the form can be submitted, we dynamically create a container for the Turnstile widget. The submit button remains disabled until the CAPTCHA is successfully completed, which prevents automated scripts from bypassing it: Submit
On the server side, the submitted token must be verified using Cloudflare’s verification API. Only if the verification succeeds should the application proceed with normal form processing:
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['cf-turnstile-response'])) {
$token = $_POST['cf-turnstile-response'];
$secret = 'YOUR_SECRET_KEY';
// Send a POST request to Cloudflare's verification endpoint
$response = file_get_contents(
'https://challenges.cloudflare.com/turnstile/v0/siteverify',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query([
'secret' => $secret,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
]),
],
])
);
$result = json_decode($response, true);
if (!empty($result['success'])) {
echo "CAPTCHA passed. Proceeding with form processing.";
} else {
echo "CAPTCHA failed. Please try again.";
}
}
This setup ensures that automated bots cannot submit your form without passing the CAPTCHA challenge.
hCaptcha
hCaptcha integration follows the same general pattern: load the script, insert the widget dynamically, disable the submit button, and verify the token on the server.
Here is an example of a generic hCaptcha implementation: Submit
Server-side verification works similarly to Turnstile:
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['h-captcha-response'])) {
$token = $_POST['h-captcha-response'];
$secret = 'YOUR_HCAPTCHA_SECRET';
$response = file_get_contents('https://hcaptcha.com/siteverify', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query([
'secret' => $secret,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
]),
],
]));
$result = json_decode($response, true);
if (!empty($result['success'])) {
echo "hCaptcha passed. Proceeding with form processing.";
} else {
echo "hCaptcha failed. Please try again.";
}
}
By structuring the code this way, developers can integrate hCaptcha into any application framework with full control over form behavior.
WordPress Implementation
WordPress requires adapting the same concepts to its hooks and APIs to ensure compatibility with themes and plugins. Scripts are enqueued with wp_enqueue_scripts, and forms are processed using admin_post hooks. The general workflow remains the same: dynamically insert the CAPTCHA, disable the submit button, store the token, and verify it server-side.
Turnstile in WordPress
Add the following to your theme’s functions.php (or custom plugin):
// Enqueue Turnstile script
add_action('wp_enqueue_scripts', function() {
wp_enqueue_script(
'cloudflare-turnstile',
'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=onTurnstileLoad',
[],
null,
true
);
});
// Dynamically inject Turnstile widget
add_action('wp_footer', function() {
?>
<?php
});
// Verify token server-side
add_action('admin_post_process_myform', function() {
if (!isset($_POST['cf-turnstile-response'])) wp_die('No CAPTCHA response found.');
$token = sanitize_text_field($_POST['cf-turnstile-response']);
$secret = 'YOUR_SECRET_KEY';
$response = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
'body' => [
'secret' => $secret,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
],
]);
if (is_wp_error($response)) wp_die('Verification error.');
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
if (!empty($result['success'])) {
wp_redirect(home_url());
exit;
} else {
wp_die('CAPTCHA verification failed.');
}
});
This code ensures the CAPTCHA integrates cleanly with WordPress forms, respecting the platform’s hooks and AJAX-friendly architecture.
hCaptcha in WordPress
The process is similar for hCaptcha. Enqueue the script, insert the widget dynamically, and verify the token server-side:
// Enqueue hCaptcha script
add_action('wp_enqueue_scripts', function() {
wp_enqueue_script('hcaptcha', 'https://js.hcaptcha.com/1/api.js', [], null, true);
});
// Insert hCaptcha widget dynamically
add_action('wp_footer', function() {
?>
<script>
document.addEventListener("DOMContentLoaded", function () {
var form = document.querySelector("#my-form");
if (!form) return;
// Create the hCaptcha container
var container = document.createElement("div");
container.className = "h-captcha";
container.setAttribute("data-sitekey", "YOUR_HCAPTCHA_SITE_KEY");
form.appendChild(container);
// Optionally disable submit until a token is present
var submit = form.querySelector('button[type="submit"], input[type="submit"]');
if (submit) submit.disabled = true;
// Enable submit when a valid token appears
var observer = new MutationObserver(function() {
var tokenField = form.querySelector('[name="h-captcha-response"]');
if (tokenField && tokenField.value && submit) {
submit.disabled = false;
}
});
observer.observe(form, { childList: true, subtree: true });
});
</script>
<?php
});
Once the user completes the CAPTCHA, hCaptcha injects a hidden h-captcha-response field into the form. The token must then be verified server-side before allowing the submission to continue:
// Verify token server-side
add_action('admin_post_process_myform', function() {
if (!isset($_POST['h-captcha-response'])) wp_die('No CAPTCHA response found.');
$token = sanitize_text_field($_POST['h-captcha-response']);
$secret = 'YOUR_HCAPTCHA_SECRET';
$response = wp_remote_post('https://api.hcaptcha.com/siteverify', [
'body' => [
'secret' => $secret,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'], // recommended but optional
],
]);
if (is_wp_error($response)) wp_die('Verification error.');
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
if (!empty($result['success'])) {
wp_redirect(home_url());
exit;
} else {
wp_die('CAPTCHA verification failed.');
}
});
This ensures hCaptcha is loaded, rendered dynamically, and securely validated before any form data is processed.
Implementing CAPTCHA challenges adds an extra layer of protection to your application. It also gives you full control over when and how the widget loads, how it interacts with form behavior, and what happens when verification succeeds or fails. This flexibility improves maintainability, makes debugging far easier, and ensures your implementation can adapt as your site or application evolves.
Security is strengthened as well, since every submission must be verified before it’s processed, reducing automated abuse and malicious activity. On any platform, CAPTCHA protection provides a strong, user-friendly security layer.

Leave a Reply