Go Back to Parent Doc

Spam Protection & CAPTCHA

Forming Forms stops spam in layers. The first layers are invisible and on by default. A CAPTCHA is free and ready when a form needs more.

LayerWhereDefault
Honeypot fieldForm block → Spam protectionOn
Submission time-trapForm block → Spam protectionOn
Per-visitor rate limitForming → Settings → Spam protection20 per hour
Akismet checkForming → Settings → Spam protectionOff
CAPTCHA (reCAPTCHA, hCaptcha, Turnstile)Provider in Settings, then per formOff

Blocked submissions are counted per day, and the Spam blocked (30 days) total appears on the Forming → Dashboard.

The honeypot

The form renders an extra text field, positioned off-screen, hidden from assistive technology and skipped by the keyboard, so no visitor ever encounters it. Bots that fill in every input fill this one too, and any submission arriving with it filled is treated as spam.

Leave it on. The only cost is one hidden input.

The time-trap

The form records when it was rendered, signed so it can’t be forged or left out. If a submission comes back in under two seconds, it’s rejected. A human hasn’t even read the labels in that time.

To tighten it:

add_filter( 'forming_min_submit_seconds', function () {
	return 5;
} );

Raise it carefully. Someone who already knows what to type into a one-field form can be quicker than you’d expect.

What a caught submission sees

A submission flagged by the honeypot, time-trap, Akismet or a low reCAPTCHA v3 score gets the ordinary success response, the same thank-you message or redirect a real visitor gets. It just isn’t stored or emailed.

Bots learn nothing from that. An error message would tell an attacker which check tripped. The trade-off is that a false positive looks like a success to the person who hit it, which is the main reason not to set the time-trap aggressively.

The rate limit and the checkbox-style CAPTCHAs are different: a real person can trip them, so they show a message.

Rate limiting

Each visitor (by IP address) can send a limited number of submissions per hour across your forms. Set Submissions allowed per visitor per hour under Forming → Settings → Spam protection. The default is 20, and 0 turns it off. Over the limit, visitors are told to try again later.

Behind a proxy or CDN such as Cloudflare, every visitor may appear to have the same IP. Use the forming_client_ip filter to read the real address from a header your proxy sets. See the Developer Reference.

Akismet

If the Akismet plugin is active and connected, turn on Check submissions with Akismet. Each submission’s name, email, website, message, IP address, browser and referring page are sent to Akismet. Submissions Akismet calls spam are silently dropped.

CAPTCHA

All three providers are free in Forming Forms.

1. Get your keys

ProviderWhere to get keysModes
Google reCAPTCHAgoogle.com/recaptcha/adminv2 “I’m not a robot” checkbox, v2 Invisible, v3 score-based (no challenge)
hCaptchadashboard.hcaptcha.comCheckbox, or Invisible (challenge only when needed)
Cloudflare TurnstileCloudflare dashboard → TurnstileManaged, non-interactive or invisible, set on the site key in Cloudflare

For reCAPTCHA, create keys for the same type you’ll choose in Forming. v2 keys don’t work with v3, and v3 keys don’t work with v2.

2. Choose the provider

Go to Forming → Settings → Spam protection, choose a CAPTCHA provider and paste the site key and secret key. Then:

  • reCAPTCHA: pick the reCAPTCHA type. For v3, set the Minimum score (0.5 suits most sites. Raise it if spam gets through).
  • hCaptcha: pick the hCaptcha widget: Checkbox or Invisible.

Click Save settings.

3. Turn it on per form

Select the Form block, open Spam protection and switch on CAPTCHA. Only forms with it on show a CAPTCHA, and the provider’s script loads only on pages with such a form. All other pages stay free of third-party scripts.

Verification happens on your server. If the CAPTCHA is missing or fails, the visitor sees a message asking them to complete it.

Privacy: CAPTCHA providers collect information about the visitor’s device and behavior. Mention the provider in your privacy policy. Its terms and privacy links are listed in the plugin’s readme under External services.

If spam still gets through

  1. Confirm the toggles are on for that form. They’re per-form, and a form copied from elsewhere may have them off.
  2. Lower the rate limit, for example to 5 an hour.
  3. Turn on Akismet if you already use it for comments.
  4. Turn on a CAPTCHA for the form. Turnstile and invisible hCaptcha add the least friction.
  5. Raise the time-trap with the filter above.
  6. Filter at the server: Cloudflare’s bot protection or your host’s firewall stops traffic before PHP runs.

Your own spam rules

Add a check with the forming_spam_check filter. Return a WP_Error to reject the submission silently, or add 'silent' => false to show your message:

add_filter( 'forming_spam_check', function ( $result, $submission ) {
	if ( is_wp_error( $result ) ) {
		return $result;
	}
	// Spam checks run before validation, so read the raw request.
	$fields  = (array) $submission->request->get_param( 'fields' );
	$message = isset( $fields['message'] ) ? (string) $fields['message'] : '';
	if ( false !== stripos( $message, 'crypto' ) ) {
		return new WP_Error( 'my_keyword', 'Spam keyword.' );
	}
	return $result;
}, 30, 2 );
Shopping Cart
  • Your cart is empty.