Get the next one in your inbox.
One email when we publish something worth reading. No spam — appropriately enough, we'd know.
Generic spam bots don't read your JavaScript — they regex your HTML for a form action and replay junk to it. Here's the fix we shipped: hide the endpoint until validation passes.

Get an instant summary, key takeaways, action items, and answers to your questions about this article.
A form's action="..." attribute is plaintext in your page source — a naive scraper can read it without running any JavaScript. We stopped putting the real endpoint there at all: the form now has no action attribute, and the URL exists only as a short encoded string inside the submit handler, decoded and used only after validation and reCAPTCHA both pass.
Most spam isn't sophisticated. It's a script that crawls the web, regex-parses every <form> tag it finds for an action attribute, and fires junk POST requests at whatever it discovers — across thousands of sites, with no browser and no JavaScript involved at all. Honeypots and reCAPTCHA are good defenses against bots that load your page. They do nothing against a bot that never loads it in the first place, because it already has your endpoint memorized from the raw HTML.
When we dug into a spam spike on this site's own contact forms, the honeypot field was filled on effectively every spam submission, and select fields showed every possible option concatenated into one value — a dead giveaway that something was auto-filling every field it found, not a person clicking through a dropdown. That's the signature of a generic scraper, not a targeted attack. See our full guide to stopping form spam for the broader picture; this post is about one specific, underused fix.
The change is small and doesn't touch how the form looks or behaves for a real visitor:
<form> tag drops its action attribute entirely — there's nothing for a static-HTML scraper to find.A visitor notices nothing. A scraper reading raw HTML finds no form action to replay against.
Be precise about the threat model here — this isn't a silver bullet. It stops bots that scrape static HTML without executing JavaScript, which describes the vast majority of mass, generic form spam. It does not stop a bot that already has your current endpoint hardcoded from an earlier scrape (the old URL is already "leaked" and needs rotating separately), and it won't stop a sophisticated, targeted attacker running a full headless browser. It's one more layer, not a replacement for honeypots or a real CAPTCHA — see reCAPTCHA vs. hCaptcha vs. Turnstile for how those compare.
Obfuscation alone doesn't help against a bot that already has your current endpoint. Pairing it with an occasional endpoint rotation — generating a fresh URL and swapping it in — invalidates every previously scraped target at once, while the obfuscation keeps the new one from being trivially harvested again. It's the same principle behind layered spam filtering: no single control does the whole job, but stacked together they close most of the gap.
No — the form looks and behaves identically. The only difference is invisible: the destination URL is assembled in JavaScript memory at submit time instead of sitting in the page's static HTML.
No. It specifically targets bots that scrape raw HTML without running JavaScript, which is the majority of generic spam. Determined, targeted attacks using a full headless browser can still see the real request once it's made.
Yes. This is a complementary layer, not a replacement — honeypots and CAPTCHA catch bots that do execute JavaScript, which this technique alone doesn't stop.
One email when we publish something worth reading. No spam — appropriately enough, we'd know.