How spam protection works
Every form has four layers of spam protection, all on by default and invisible to real visitors. There is no CAPTCHA. This page explains each layer, what a visitor sees when it stops a submission, and the settings you can change.
The layers
Section titled “The layers”| Layer | What it catches | What the visitor sees | Stored? |
|---|---|---|---|
| Honeypot | A hidden field, labelled “Leave this empty”, that people never see but bots fill in. Its name is different for each form. | The normal success message. | Yes, as spam |
| Timing check | Submissions sent less than 3 seconds after the form was shown. | Please wait a moment before submitting. | No |
| Duplicate check | The same submission arriving twice within 60 seconds, such as a double tap. | The first copy’s own result once it is saved; Your first attempt is still being processed. Please wait a few seconds, then try again. while it is not. | Only the first |
| Rate limits | Too many submissions from one IP address, or to one form. See below. | Too many submissions. Please try again later. | No |
The honeypot answers with a success message on purpose, so a bot learns nothing. The submission is kept as a spam entry: it sends no email, fires no webhook and starts no workflow, and it is hidden in Form Entries unless Include Spam is ticked. If a real person filled the honeypot, usually through a password manager, tick the entry and choose Mark as Not Spam from Bulk actions. At most 50 honeypot entries are kept per form each hour, so a bot attack cannot fill the database.
The duplicate check never says “Thanks” for a copy unless the first one was really saved.
Rate limits
Section titled “Rate limits”| Limit | Default | Can you change it? |
|---|---|---|
| One IP address, one form | 5 submissions an hour | Yes, per form |
| One IP address, all forms together | 20 submissions an hour | No |
| All visitors, one form | 30 submissions a minute | With a filter, see below |
The form-wide limit shows This form is receiving too many submissions. Please try again later. Every attempt counts toward the limits, including ones then refused for a missing required field.
Options
Section titled “Options”These go in settings.spam_protection:
"spam_protection": { "honeypot": true, "timing_check": true, "min_submission_time": 3, "rate_limit": {"max": 5, "window": 3600}}| Option | What it does | Default |
|---|---|---|
honeypot | Add the hidden honeypot field. | true |
timing_check | Refuse submissions sent too soon after the form was shown. | true |
min_submission_time | The minimum, in seconds. | 3 |
rate_limit.max | Submissions allowed from one IP address to this form in the window, from 1 to 100. | 5 |
rate_limit.window | The window in seconds, from 60 (a minute) to 86400 (a day). | 3600 |
Raise rate_limit.max for forms many people submit from one network, such
as an event sign-up used on a school or office connection.
For developers
Section titled “For developers”- Behind a proxy or CDN, every visitor can appear to come from the proxy’s
address and share one rate limit. List your proxy addresses with the
pforms_trusted_proxiesfilter so the visitor’s own address, fromX-Forwarded-For, is used instead. pforms_global_rate_limitchanges the 30-a-minute form-wide limit; it receives the limit and the form ID.pforms_spam_detectedfires when the honeypot or timing check stops a submission, andpforms_rate_limit_exceededwhen a per-form limit is hit.- The connector’s
formengine_test_submitdoes not run these checks.
Limits and common problems
Section titled “Limits and common problems”- Testing too fast. Submitting within 3 seconds of loading the page, as browser autofill and test scripts do, shows Please wait a moment before submitting. Wait a few seconds.
- “Nothing arrived but the form said thank you.” The honeypot stopped it. Tick Include Spam in Form Entries to find it. A password manager or autofill that fills every field, including hidden ones, can trigger the honeypot.
- Spam still gets through. Mark it with Mark as Spam on the entry; it is hidden from the list and counts. There is no learning filter.