GMax Mart
Home Services Pricing Portfolio FAQ Reviews Blog Support Careers Change Language

Forms & Privacy

Honeypots, time checks and rate limits: CAPTCHA-free spam defences

· 7 min read

Honeypots, time checks and rate limits: CAPTCHA-free spam defences

Most automated form spam is not clever. It is a script that requests your page, fills every input it can find, posts the result and moves on to the next site in its list, thousands of times an hour. Because of that, three simple server-side techniques block a large share of it without asking the visitor to do anything. This article explains CAPTCHA-free spam protection using honeypot fields, submission time checks and rate limits: how each one works, how to implement it without breaking accessibility, where each one fails, and how to combine them into a single decision.

None of these will stop a determined human targeting your site specifically. All three will stop the bulk traffic that makes up the majority of junk in a small business inbox.

Honeypot fields: a trap only bots fall into

A honeypot is an extra input in your form that real visitors never see and never fill. Your server rejects any submission that contains a value in it. Simple bots fill every field they find, so they mark themselves.

Implementation notes

  • Name it plausibly. A field called "url", "website" or "company_fax" is more tempting to a bot than one called "honeypot".
  • Hide it with CSS, not the hidden input type. Position it off-screen or set it to display none through your stylesheet. Many bots ignore type="hidden" fields entirely, which defeats the purpose.
  • Protect real users who cannot see CSS. Screen readers may still announce the field, and browser autofill may fill it. Add aria-hidden and tabindex of minus one via your developer, give it a label that says to leave it empty, and switch autocomplete off.
  • Fail quietly. Return the normal thank-you response rather than an error. If the bot learns it was blocked, it may adapt; if it thinks it succeeded, it moves on.
  • Log the rejection. Keep the submission in a table marked as blocked so you can confirm you are not silently discarding real enquiries.

Weaknesses

Bots that render the page in a real browser engine see the field is invisible and skip it. Password managers and browser autofill occasionally populate a field named "address" or "company", which produces false positives, so choose names that autofill will not recognise. And any bot written specifically for your site will simply be told which field to ignore.

Time checks: nobody fills a form in two seconds

A human needs time to read labels and type. A script posts immediately. By recording when the form was served and comparing it with when the submission arrived, you can reject anything impossibly fast.

Implementation notes

  1. Record the render timestamp server-side, keyed to the session, or put a signed timestamp in a hidden field. Never trust a plain, unsigned timestamp from the client, because it can be altered.
  2. Set a minimum that fits the form. Three seconds is reasonable for a short contact form; a long application form can use more.
  3. Set a maximum too. If a form token is older than, say, two hours, the page was probably scraped and replayed, or the visitor left the tab open overnight. Expire it and ask them to resubmit, preserving their typed values.
  4. Combine the timestamp with your framework's CSRF token, which already ties the submission to a session and expires on its own.

Weaknesses

A bot can pause before posting; waiting five seconds costs it almost nothing at scale. Legitimate users can also trip the rule, for example when a browser restores a form on a page reopened from history, or when someone pastes prepared text and submits instantly. Keep the minimum low and treat a fast submission as one signal rather than a verdict on its own.

Rate limits: capping how often anyone can post

A rate limit restricts how many submissions a single source may make in a period, for example three per IP address per fifteen minutes and ten per hour. It does not identify bots; it caps the damage any one of them can do.

Implementation notes

  • Enforce it server-side, at the application or web server level. Most frameworks have throttling built in, and reverse proxies such as Nginx or a CDN can apply limits before requests reach your application.
  • Choose the right key. IP address is the usual one, but consider also limiting by email address or phone number for signup and OTP forms, where one attacker may rotate addresses.
  • Read the client address correctly. Behind Cloudflare or a load balancer, the direct connection address is the proxy. Configure trusted proxies so you throttle the visitor rather than everyone behind the same edge.
  • Return HTTP 429 with a clear, human-readable message and, where useful, a Retry-After header.
  • Apply harder limits to expensive actions: anything that sends an SMS, an OTP or a payment request deserves a tighter cap than a plain contact form.

Weaknesses

Shared connections are the big one. An office, a college or a mobile carrier's network can put hundreds of genuine users behind one address, so a strict per-IP limit blocks real customers. Distributed spam from many addresses passes a per-IP limit entirely. Set limits generously enough that ordinary use never touches them.

Combining the three into one decision

Used alone, each technique has an obvious hole. Used together, they cover most of each other's gaps, and the best way to combine them is a score rather than a chain of hard rejections.

Give each signal a weight: honeypot filled is strong, submission under two seconds is moderate, over the rate limit is strong, message contains five links is moderate, no CSRF token is strong. Add them up and choose one of three outcomes:

  • Low score: accept normally.
  • Middle score: accept but flag for review, or hold the message in a moderation queue rather than emailing it out.
  • High score: reject, quietly, and log it.

This approach means a single false signal never costs you an enquiry. It also gives you data: after a month of logs you can see which rule fires most and tune the weights from evidence instead of guesswork.

Put it in place and check it fortnightly

Implement the honeypot and the time check first, since they take an hour of developer time and need no third-party service. Add a rate limit at the server or CDN level next. Then, for the first few weeks, open the blocked-submissions log fortnightly and read a sample to confirm nothing genuine is being caught. If your forms are part of a bigger application where signups, OTPs and payments all need protecting, our software development team can build this scoring logic once and reuse it across every endpoint.

Frequently asked questions

Do honeypot fields affect accessibility?

They can, if implemented carelessly. Hiding the field with CSS while also marking it hidden from assistive technology and removing it from the tab order keeps screen reader users from ever encountering it.

Can I use these techniques with a WordPress form plugin?

Most popular form plugins include honeypot and time-check options in their settings, sometimes under names like "anti-spam" or "minimum submission time". Check the settings before installing an extra plugin for the same job.

What should happen to blocked submissions?

Store them for a limited period, such as 30 days, in a table or folder that only your team can see, then delete them. Keeping them lets you spot false positives; deleting them on schedule keeps stray personal data from piling up.

Will these methods stop AI-generated outreach messages?

Not on their own. Messages sent by a real browser at human speed pass all three checks. Content rules, a moderation queue and email filters are the practical answer to that kind of spam.

Thinking about a website?

See what a package covers and what it costs, or ask us about your own project.

Read next

Thinking…