Skip to content
S-11

Forms are broken or full of spam

Spam floods, CAPTCHA errors, forms that fail on submit, or entries with no email.

Do this first

Your first three moves

  1. Submit the form in a private window with developer tools open. Note the console error and the status code of the POST.
  2. CAPTCHA error after a domain change? Add the new hostname to the site key's domain list in reCAPTCHA or Turnstile.
  3. Spam flood? Run wp option get users_can_register (should be 0) and add a honeypot or Turnstile before a harsher CAPTCHA.

Diagnose it

Work out what is really wrong

What you are seeing

Form trouble splits two ways: forms that block real people, and forms that let junk through. Fixes for one often cause the other, because a harsher CAPTCHA stops customers too.

What you seeWhat it usually means
ERROR for site owner: Invalid domain for site key in the reCAPTCHA boxThe key’s domain list does not include this hostname. Common after a domain change or a launch from staging.
ERROR for site owner: Invalid key typeA key made for one reCAPTCHA type (such as v2 checkbox) is used where the plugin expects another (such as v3).
Turnstile error 110200Domain not authorized. The hostname is missing from the widget’s Hostname Management list.
Real visitors told they look like spam or failed the CAPTCHAA reCAPTCHA v3 score under the plugin’s threshold, an expired token, or a wrong secret key on the server.
The link you followed has expired.A WordPress nonce check failed: a cached page holding an old token, or an upload bigger than PHP accepts.
Cookie check failed with code rest_cookie_invalid_nonceA form posting to the REST API with a stale nonce, usually from a cached page.
A success message, but no stored entry and no emailThe submission did not complete on the server, or the plugin does not store entries.
An entry stored, but no emailMail delivery, not the form. See the email stopped working triage.
403 Forbidden on submitA firewall or ModSecurity rule matched the message.
413 Request Entity Too Large, or The uploaded file exceeds the upload_max_filesize directive in php.ini.The upload is larger than the web server or PHP allows. Nginx allows 1 MB unless configured otherwise.
Floods of junk entries, new subscriber accounts, or commentsBots using an open form, registration or comments.

Confirm it in two minutes

1. Watch the submission in the browser. Open the form in a private window, press F12, open the Network tab, and submit. Find the POST request: to admin-ajax.php, a /wp-json/ address, or the page itself. Good: 200 and a success reply. Bad: 200 with an error in the reply body (the plugin rejected it; read the message), 403 (firewall or nonce), 413 (size), 500 (a PHP error). No request at all means a JavaScript error stopped the form; check the Console tab.

2. Find the CAPTCHA key the page uses.

curl -s https://example.com/FORM_PAGE/ | grep -oE '(render=|data-sitekey=.)[0-9A-Za-z_-]{20,}' | sort -u

Run it in your own computer’s terminal (on Windows, type curl.exe). Replace example.com with your domain and FORM_PAGE with the path of the page holding the form. It prints site keys from the reCAPTCHA script address or the widget’s data-sitekey. Good: one key, found in your reCAPTCHA or Turnstile account with this hostname on its domain list. Bad: two keys (two plugins each adding a CAPTCHA), or a key in no account you control.

3. Test that the secret key is accepted.

curl -s -d 'secret=SECRET_KEY&response=test' https://www.google.com/recaptcha/api/siteverify

Run it on your own computer. SECRET_KEY is the secret saved in your plugin’s settings. -d sends it as a POST with a fake token. Good: only invalid-input-response, meaning the secret works and the fake token was rejected. Bad: invalid-input-secret, meaning the secret is wrong, deleted or for another key. For Turnstile, send the same request to https://challenges.cloudflare.com/turnstile/v0/siteverify. Do not paste the secret anywhere public.

4. Check registration and comment exposure.

wp option get users_can_register
wp option get default_role
wp comment list --status=hold --format=count

Run these in an SSH terminal inside the site’s folder (the one with wp-config.php). Good: 0 unless you need public sign-ups, subscriber as the default role, and a small moderation queue. Bad: 1 on a site that never needed accounts, or a default role of administrator or editor, which is a sign of a compromise. Follow the hacked site steps if so.

5. Check the PHP upload limits.

wp eval 'echo ini_get("upload_max_filesize"), " / ", ini_get("post_max_size"), "\n";'

Run it in the same terminal. Good: both above the largest file your form accepts, post_max_size the larger. WP-CLI can read a different php.ini, so confirm under Tools, Site Health, Info, Server. A 413 is the web server’s limit, which your host sets.

Most likely causes, in order

  1. The CAPTCHA key does not cover the domain. Tell: errors began after a domain change, a launch from staging, or a switch between www and non-www, and the widget shows a domain error. Fix: add the new hostname to the key’s domain list in the reCAPTCHA admin console or Turnstile’s Hostname Management, or create keys for the new domain and save them in the plugin.
  2. The CAPTCHA key was deleted, rotated or stopped scoring. Tell: check 3 returns invalid-input-secret, or forms fail with no change on your side. Google moved reCAPTCHA keys into Google Cloud projects; the free tier there covers 10,000 assessments a month, and use above that needs billing. Fix: find the key’s project, check its status and usage, and save fresh keys if needed.
  3. Cached pages with stale nonces. Tell: forms work when you are logged in but fail for visitors, mostly on pages cached for many hours. A WordPress nonce lasts 24 hours by default, in two 12-hour halves. Fix: cache form pages for less than 12 hours or exclude them. The nonce field guide covers plugin settings.
  4. Two spam layers fighting. Tell: check 2 finds two keys, or a security plugin adds a second CAPTCHA. Fix: keep one.
  5. A firewall blocking real messages. Tell: a 403 in check 1, triggered by certain words, links or code in the message. Fix: send the rule ID from the host’s log so they can adjust it.
  6. An open door for bots. Tell: registration open with no need, a form with no honeypot or CAPTCHA, or comments open on years of old posts. Fix: close registration, add a honeypot or Turnstile, and set Settings, Discussion to close comments on older posts automatically.
  7. Upload limits. Tell: only large files fail, with a 413 or the upload_max_filesize message. Fix: raise the PHP and web server limits and set the form’s maximum below them.

What it usually is not

  • A CAPTCHA that needs to be stricter. When real people fail, stricter makes it worse. Check the key and domain first.
  • Bots beating the CAPTCHA, every time. Low-volume, well-written sales pitches are often typed by people. No CAPTCHA stops a person; content filtering and blocklists do.
  • Form spam, when the address is published on the page. Harvested addresses get spam directly. If the message headers show it never passed through your server, the form is not the source.

What to send your host or the relevant provider

  • To your host: the form URL, the time in UTC, your public IP, and the status code from check 1.
  • A request for firewall or ModSecurity log lines for that request, with the rule ID.
  • For upload errors: the largest file you need to accept and the current limits from check 5.
  • To the form plugin’s support: plugin name and version, the reply body from the Network tab, console errors, and which caching plugin you use.
  • To whoever owns the CAPTCHA account: the site key (never the secret), the domains listed on it, the error text, and when the domain changed.

The full fix

Field guides for this symptom

Search the field manual

What is going wrong?

Press / to search from any page, Esc to close