Security (Imunify360, ModSecurity)

The Importance of Captcha in Contact Forms and How to Implement It

By the Domain India teamPublished 7 min read
Knowledge base article
Contents (10 sections)

A contact form with no spam protection is found by bots within days, and after that your inbox fills with junk, fake enquiries and phishing links. A CAPTCHA is a check that lets people through and stops most automated submissions. This guide explains what a CAPTCHA does and does not protect, how to choose between Google reCAPTCHA, Cloudflare Turnstile and hCaptcha, and how to add one to a PHP or WordPress form, with server-side verification that actually works on shared hosting.

Key takeaways

Add a CAPTCHA when a honeypot field and a rate limit are no longer enough to stop form spam. Cloudflare Turnstile and reCAPTCHA v3 are invisible to most visitors, and reCAPTCHA v2 and hCaptcha show a checkbox. Whichever you choose, the widget in the browser is only half the job: your server must send the token to the provider and reject the message unless the answer is a success.

1. What goes wrong without spam protection

Spam floods your inbox
Bots submit hundreds of adverts and links, and real enquiries get lost among them.
Your domain gets a bad reputation
If the form emails the visitor a copy, bots use it to send spam through your site, and your mail starts landing in junk folders.
Phishing and malware links
Fake "customer" messages carry links that your staff may click.
Wasted resources
Every bot submission runs your PHP and sends mail, which counts against your hosting limits.

The old claim that a missing CAPTCHA "leads to data breaches" or DDoS attacks is overstated. A CAPTCHA protects one form from automated submissions. It does not protect a login page you did not put it on, it does not stop a DDoS, and it does not fix insecure code. Treat it as one layer.

2. Try the invisible layers first

Before you add any widget, most spam can be stopped with three checks you control in your own code:

  1. A honeypot field. A hidden input that people never see and bots fill in. If it has a value, drop the message silently.
  2. A minimum fill time. People take more than a few seconds to write a message. Reject forms submitted within about 3 seconds of loading.
  3. A rate limit per IP address. Allow a handful of submissions per hour from one address.

The complete, tested PHP form with all three is in Secure PHP contact form: complete code and instructions. Add a CAPTCHA on top when spam still gets through.

3. Choosing a CAPTCHA service

ServiceWhat visitors seeCostGood to know
Cloudflare TurnstileUsually nothing; sometimes a short checkFreeYour site does not need to be on Cloudflare to use it
Google reCAPTCHA v3Nothing; returns a score from 0.0 to 1.0Free tier; check Google's current limitsYou choose the score threshold, often 0.5
Google reCAPTCHA v2"I'm not a robot" checkbox, sometimes image puzzlesFree tier; check Google's current limitsThe most familiar option; puzzles annoy some visitors
hCaptchaCheckbox, sometimes image puzzlesFree planA privacy-focused alternative to reCAPTCHA

For most small business sites, Turnstile is the easiest start: it is free, usually invisible and simple to verify. Choose reCAPTCHA if you already use Google services and want its scoring.

Privacy and consent

Every CAPTCHA service loads a script from its provider and processes data about the visitor, such as the IP address. Mention the service in your website's privacy policy.

4. How a CAPTCHA works: two halves

  1. Get two keys.
    Register your domain with the provider. You receive a site key, which is public and goes in your HTML, and a secret key, which stays on your server.
  2. Add the widget.
    The provider's script runs in the visitor's browser and adds a one-time token to the form when the check passes.
  3. Verify on the server.
    Your PHP handler sends the token and your secret key to the provider's verification address and gets back a yes or no.
  4. Act on the answer.
    Send the email only when the provider says the token is valid. Otherwise show "Please complete the spam check" and send nothing.
A widget with no server check protects nothing

If your server never verifies the token, a bot simply posts straight to your handler and skips the widget. Step 3 is the part that stops spam.

5. Add the widget to your form

This example uses Cloudflare Turnstile. Place the script once on the page and the widget inside your form:

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

<form action="send.php" method="post">
  <!-- your name, email and message fields -->
  <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
  <button type="submit">Send</button>
</form>

For reCAPTCHA v2, the script is https://www.google.com/recaptcha/api.js and the widget is div class="g-recaptcha". For hCaptcha it is https://js.hcaptcha.com/1/api.js with div class="h-captcha". Each adds its own token field to the form: cf-turnstile-response, g-recaptcha-response or h-captcha-response. Follow the provider's current documentation for exact names.

6. Verify the token in PHP

Keep the secret key out of your web root, for example in a file above public_html, and load it from there. This helper works with all three providers. It uses cURL where it is available and falls back to file_get_contents where cURL is disabled:

php
<?php
// captcha.php — keep this file above public_html
const CAPTCHA_SECRET = 'YOUR_SECRET_KEY';
const CAPTCHA_VERIFY_URL = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
// reCAPTCHA: https://www.google.com/recaptcha/api/siteverify
// hCaptcha:  https://api.hcaptcha.com/siteverify

function captcha_passed(string $token): bool
{
    if ($token === '') {
        return false;
    }
    $data = http_build_query([
        'secret'   => CAPTCHA_SECRET,
        'response' => $token,
        'remoteip' => $_SERVER['REMOTE_ADDR'] ?? '',
    ]);

    if (function_exists('curl_exec')) {
        $ch = curl_init(CAPTCHA_VERIFY_URL);
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $data,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
        ]);
        $body = curl_exec($ch);
        curl_close($ch);
    } else {
        $context = stream_context_create(['http' => [
            'method'  => 'POST',
            'header'  => "Content-Type: application/x-www-form-urlencoded\r\n",
            'content' => $data,
            'timeout' => 10,
        ]]);
        $body = @file_get_contents(CAPTCHA_VERIFY_URL, false, $context);
    }

    if ($body === false) {
        return false; // provider unreachable: fail closed
    }
    $result = json_decode($body, true);
    return is_array($result) && ($result['success'] ?? false) === true;
}

Then, in your form handler, before anything is sent:

php
<?php
require __DIR__ . '/../captcha.php';

$token = $_POST['cf-turnstile-response'] ?? '';
if (!captcha_passed($token)) {
    http_response_code(400);
    exit('Please complete the spam check and try again.');
}
// ...validate the fields, then send the email

For reCAPTCHA v3, also read $result['score'] and $result['action'], and reject scores below your threshold. For every provider, you can compare $result['hostname'] with your own domain for extra safety.

7. WordPress: use your form plugin's setting

On WordPress, do not edit theme files for this. Popular form plugins such as Contact Form 7, WPForms and Fluent Forms have a built-in setting for reCAPTCHA or Turnstile, or support it through an add-on: you paste the site key and secret key, and the plugin does the server check. Turn on the plugin's honeypot option as well. See the top WordPress plugins for contact forms for choosing one.

8. Test it and keep an eye on it

  1. Submit the form normally. The message should arrive.
  2. Submit it with the widget removed (or post to the handler with a tool such as curl). It must be rejected.
  3. Test on a phone and in a private window, where CAPTCHA checks are often stricter.
  4. Watch for a week. If real people complain, lower the reCAPTCHA v3 threshold or switch to an invisible option. If spam continues, check that the server check is really running.

9. Running this on Domain India hosting

On Domain India shared hosting, a few server settings affect this code:

  • cPanel hosting: curl_exec works, so the helper uses cURL. Some other functions are disabled for security; see PHP disabled functions on shared hosting.
  • DirectAdmin hosting: on most sites curl_exec is disabled and allow_url_fopen is on, so the helper falls back to file_get_contents automatically. Test the form on your plan.
  • Sending the email: on cPanel, send with PHP mail() and the -f option rather than SMTP. The method is in How to use PHPMailer for contact forms.

If your site is built with the AI Website Builder, the contact form is part of the builder, and you do not add CAPTCHA code yourself.

Frequently asked questions

Do I need a CAPTCHA on my contact form?

Not always. A hidden honeypot field, a minimum fill time and a rate limit per IP address stop most automated spam. Add a CAPTCHA such as Cloudflare Turnstile or Google reCAPTCHA when spam still gets through.

Which CAPTCHA is best for a small business website?

Cloudflare Turnstile is a good default: it is free, usually invisible to visitors, and your site does not need to use Cloudflare. Google reCAPTCHA v3 is also invisible and gives each visitor a score. reCAPTCHA v2 and hCaptcha show a checkbox and sometimes image puzzles.

Why am I still getting spam after adding reCAPTCHA?

Usually because the token is never checked on the server. Bots skip the widget and post straight to your form handler. Your PHP code must send the token and your secret key to the provider's verification address and reject the message unless the reply says success.

Where should I keep the CAPTCHA secret key?

On the server only, in a file outside the public web folder, for example above public_html. Never put the secret key in HTML or JavaScript. The site key is public and is the only key that goes in the page.

Does a CAPTCHA protect my website from hackers?

No. It stops automated submissions on the form where you add it. It does not stop DDoS attacks, protect other pages or fix insecure code. Keep your software updated and validate every form field on the server.

My PHP CAPTCHA check fails on DirectAdmin hosting. Why?

On most Domain India DirectAdmin sites the curl_exec function is disabled. Use file_get_contents with a stream context to call the verification address instead, which works because allow_url_fopen is on, and test the form on your plan.

Ready to build a safer contact form? Start with the secure PHP contact form guide, or put your website on cPanel hosting. If the verification call fails on your plan, open a ticket with the error message.

Need help with your contact form?

Tell us your domain, the page with the form and what happens when you submit it, and we will check the server side of the setup for you.

Open a support ticket

Ready when you are

Get cPanel hosting from ₹125/mo + GST

See plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app