Last updated: 2026-02-04

We all make mistakes. Mine? I deployed a new version of the site and forgot to protect the /register route. Then I went AFK. By the time I checked back, over 250 fake accounts had been created by bots.
This happened while working on StatusPage.me, and it was a good reminder that “small” auth endpoints still need boring, reliable protection.
Related reading: product features, Statuspage alternatives, and the incident comms primer What Is a Status Page?.
The good news? I had already been working on a small invisible captcha library - a honeypot-based solution that’s effortless for users but brutal on bots. I finalized it, integrated it, and released it as gocaptcha.
How do you stop spam signups with a honeypot captcha?
Add a hidden input field that real users never fill, then reject requests where that field is populated. Bots tend to fill every field they can see in the HTML, so the honeypot becomes a low-friction signal. Pair it with basic rate limiting and logging so you can block repeat offenders without hurting legitimate signups. The result is a simple control that costs almost nothing in UX.
What I did
- I added a simple hidden input field to the registration form. It’s named something like
nicknameand styled so that users never see it. - On form submission, the server checks whether the field is filled. If it is, the request is likely from a bot and is rejected.
- I wrapped the logic in a clean Gin middleware and released it as
gocaptcha- so any Gin-based app can plug it in with minimal effort.
Why honeypots work 🍯
Spam bots typically fill every field they find in a form. By introducing a field that legitimate users will never touch - but bots will - we can confidently detect automated signups with virtually no user friction.
It’s simple, elegant, and surprisingly effective.
The results
After deploying the honeypot middleware in my Gin app, the effect was immediate.
Spam signups dropped from hundreds to zero - instantly.

💡 Here’s a glimpse from the admin dashboard, showing the captcha logs and the now-empty /register route:

How you can use it
1. Add the hidden input to your form
<form action="/register" method="post">
<input type="text" name="nickname" style="position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;" autocomplete="off">
<!-- visible fields here -->
</form>
2. Validate on the server using gocaptcha
import (
"github.com/gin-gonic/gin"
"github.com/dragstor/gocaptcha"
)
r := gin.Default()
cap := gocaptcha.New(gocaptcha.Config{
ShowBadge: true, // show small lock badge (optional)
BadgeMessage: "Protected by GoCaptcha", // badge text
RateLimitTTL: time.Minute, // per-IP window
RateLimitMax: 10, // max requests/window
EnableStorage: true, // enable SQLite logs + seeding
DBPath: "./captcha.db", // defaults to ./captcha.db if empty
BlockThreshold: -5, // block when score <= threshold
// Bypass OAuth callbacks:
SkipPaths: []string{"/auth/", "/oauth2/"},
TrustProxyHeaders: true, // respect X-Forwarded-For when behind a proxy (I use Caddy reverse proxy)
})
r.POST("/register", func(c *gin.Context) {
if cap.CheckRequest(c.Request) {
// redirect to a login page if bot detected, making them feel like they succeeded
c.Redirect(http.StatusSeeOther, mainDomain+"/user/login")
return
}
// If middleware passes, continue with registration logic
})
⚠️ A few notes
- Honeypots are simple and highly effective, but they’re not bulletproof. For maximum protection, combine them with rate limiting, IP filters, and email verification.
- Choose a believable name for the hidden field - something like
"nickname"or"middle_name". Avoid anything obviously fake. - Don’t rely on JavaScript alone to hide the field. Use CSS, so non-JS bots still fall into the trap.
Want to try it yourself?
Grab gocaptcha from GitHub: https://github.com/dragstor/gocaptcha
It’s lightweight, Gin-native, and it completely solved my bot problem.
If you also care about keeping public pages privacy-friendly, see: Privacy-First Web Analytics for Status Pages
Tags: captcha, spam, honeypot, gin
Want to see it in action? Head to the live demo:
FAQ
Are honeypots enough on their own?
They are a strong first line, but the best setup combines honeypots with rate limiting, email verification, and sane logging.
Will this block real users?
Not if implemented correctly. Real users never see or interact with the honeypot field.
Do I need JavaScript for a honeypot?
No. A server-validated honeypot works without JavaScript and still catches many bots.
Why redirect bots instead of returning an error?
Redirecting to a login page can reduce bot retries by making them “feel” successful.


