It’s an all-too-common narrative. You’ve worked closely across engineering, marketing, and product to build compelling “contact us” forms – and suddenly, they’re filling up with spam. Now, all the previously happy stakeholders are concerned and want to see the spam form submissions stopped, asap.
We provide a quick tutorial below for removing that contact form spam without a CAPTCHA by using Stytch Device Fingerprinting. Feel free to skip ahead. Otherwise, let’s dig into the problem a bit more.
Why is this spam happening? Is it worth the effort to stop spammy form-fills? And if so, what are the options to prevent spam submissions?
These were the questions that we asked ourselves at Stytch recently, when junk leads on stytch.com/contact were frustrating Sales and skewing Marketing numbers.
Spammy contact form submissions and invalid traffic have a very real cost for both engineering and go-to-market teams.
For engineering and data teams, the primary cost driver is time – time answering questions from Marketing or Sales on why this is happening, time spent scrubbing data to remove the bad leads, and time exploring solutions that may not work – or may only partially solve the problem.
For Marketing teams, spammy contact form signups skew data and reporting – both internally, and in the conversion data that’s reported back to platforms like Google Ads or LinkedIn ads. Plus, spam that comes through ad platforms can also consume valuable ad dollars that could otherwise be spent on real prospects.
And for Sales teams, spam form submissions lead to wasted time sorting spam from legit sign-ups – which also means that legitimate leads may have to wait longer for a response, or even that legitimate leads may fall through the cracks or get lost amidst the spam. Leads are 100x more likely to respond when they receive a follow-up within 5 minutes; so even wasting a minute or two every hour clearing out spam leads can add up to real dollars lost.
One of the first questions to ask when trying to understand and block fraud is why. Bad actors don’t usually spam just to spam; most likely, they’re spamming your form, calendar, or login flow because they believe there’s value they can extract.
In our experience, one of the most common sources of form spam is ad fraud. In a form of ad fraud called click fraud, bad actors will use bots of headless browsing to click ads and then fill out contact forms or book meetings to successfully trigger a ‘conversion event.’ Sometimes, click fraud might be perpetrated by your competitors – who know that by triggering clicks and conversions against your ads, they can deplete your paid ad budget, allowing their ads or organic results to show instead. In other cases, the ad networks themselves may engage in click fraud, since elevated clicks and conversions from their ad platform might convince companies to spend even more money with them.
These are only two examples of the financial incentives that bad actors have to spam forms; others might be less even more nefarious – like testing your forms for vulnerabilities, including susceptibility to injection attacks. Not fun.
There are a range of options to stop bots from filling out forms on your site (and therefore – wasting your team’s time and energy). Each of them have pros and cons:
While this is the option that many people turn to first, filtering spam contact form signups purely based on the submission content often isn’t good enough. While some spammy submissions can be easily identified programmatically and filtered out (for example – names that contain ‘test’, ‘aaa’, or a URL), bad actors who are spamming forms at scale are more sophisticated, and will use realistic values to avoid rule-based logic. Here’s a great example:
Upon human review, this submission is clearly invalid – but simple rule-based filtering may not catch it.
CAPTCHAs, and in particular Google reCAPTCHA, are among the most common solutions to prevent spam form signups. Some companies like Hubspot offer reCAPTCHA integrations for their forms by default given how widespread this problem is.
However, CAPTCHAs have some downsides – they create friction for real users, who have to pause while filling out your form to check a box, select crosswalks, or solve a puzzle. Traditional CAPTCHAs are also far from bot-proof; there are a wide range of services like anti-captcha or 2captcha that solve CAPTCHAs for fractions of a cent.
That said, if your spam problem is fairly mild, or the financial incentives for the spammers are low, a CAPTCHA may be enough, and is typically simple to set up and deploy.
The preferred solution among many developers to trap spambots is to use a ‘Honeypot.’ Setting up a honeypot essentially just means creating a decoy to trick bad actors into identifying themselves.
The most common honeypot strategy for contact forms is to include an ‘invisible field,’ or a form field where the display property is set to ‘none.’ Spam bots filling out the form with junk signups may not realize that the field isn’t visible, and will fill it out anyway, identifying themselves as automated actors.
Stack Overflow and other sites offer a wide range of explanations for how to set effective honeypots to stop form spam; however, as evidenced by the follow-up article on nuclear honeypots, automated form spammers can easily become sophisticated enough to avoid basic traps.
In addition, these solutions are usually optimized for spammers using scripts or CURL to interact with your site, and aren’t equipped to stop other types of bot traffic like headless browsing. As a result, honey pots are a great example of an initial fix that may help, but that often isn’t a sustainable end to form spam.
An alternative option to prevent spammy form submissions is to use browser fingerprinting or device fingerprinting to both generate unique visitor IDs and to distinguish real users from bots. Browser fingerprinting works by looking at a range of factors – such as a computer’s browser, user agent, IP address, hardware configuration, and more – to develop a unique identifier for each visitor. That identifier is typically coupled with information about if the visitor is a bot or is engaging in any type of deception, and so therefore should be challenged or blocked.
By using device fingerprinting to distinguish real users from bots, and to uniquely identify visitors, it’s possible both to programmatically block or challenge submissions from bots and automation, as well as to build rules to individually ban human users who are abusing resources.
One downside of browser fingerprinting is that if your goal is to entirely stop spam form-fills, a fingerprinting verdict alone is not enough; you also need to build a mechanism to act on that knowledge, for example by showing a CAPTCHA or requiring authentication to continue when a user’s status is unclear. However, this allows users who are clearly above-board to be quickly routed through to marketing and Sales systems, while bots or suspicious actors can either be challenged programmatically, or their form submissions can be reviewed upfront before being filtered onward into Sales systems.
At Stytch, we’re biased because we have our own Device Fingerprinting solution. While it’s coupled by default with our authentication systems, it can also be used standalone to protect any resource that may be at risk of abuse – including, you guessed it, contact us forms.
When our team started seeing an uptick in form spam, our Web team turned to device fingerprinting to block spam signups. This reduced frustration and ad spend for our marketing team and saved time for our Sales team in reviewing low-quality leads. And for the Web team, this stopped the influx of Linear tickets from Sales and Marketing reporting spam in the first place!
The good news: using device fingerprinting, we were able to spin up a quick solution to block spam signups without adding user friction.
Following the installation guide, we updated the page that contains our contact us form to include the very simple device fingerprinting script in the header:
We then configured the form to call the GetTelemetryId() whenever the form is submitted. As a result, each form submission is also coupled with a unique telemetry ID. If your goal is to block form submissions before they begin, you could also call this function on page load; we chose to call it on submission since our focus was not on preventing bots from accessing our site as a whole, but rather on preventing spammy signups from being passed to our Sales systems (in this case, Hubspot).
As a result, each form-fill now logs the basic form fields – name, email, company size, and such – but also includes a telemetry ID. We can then use this telemetry ID on the server side – so therefore, fully hidden from bad actors – to look up a ‘verdict’ from our device fingerprinting endpoint. This lookup provides a more holistic set of identifiers (e.g. a browser, network, and visitor fingerprint), a verdict (ALLOW, BLOCK, or CHALLENGE), and some additional context on why the verdict was returned.
Here’s the basic idea of what the architecture and interactions look like:
Since our priority is preventing spammy signups from entering our Sales funnel, rather than exposing a CAPTCHA or similar to users, we leverage the verdict and reasons on the backend to filter out questionable submissions. Submissions that return an ‘ALLOW’ verdict are almost always from real humans, and are passed directly to Hubspot via an API call, so that BDRs can quickly work the leads.
Submissions that return a ‘CHALLENGE’ or ‘BLOCK’ verdict are logged to our backend for periodic review by our team – who can see the form submission details, the fingerprinting identifiers, and the reasons for the verdict (typically – clear signs of automation or deception) at a glance. This ensures that we don’t lose or provide prohibitive friction for real users. After all, some legitimate developers take steps to protect their privacy, such as disabling JavaScript, that may result in a challenge verdict. These submissions remain available in our logs and can be pushed to our Sales Systems if needed, but don’t clog up our systems and our data.
Another advantage of using device fingerprinting is that in addition to programmatically stopping bots and users that are engaged in some sort of deception, we can also manually block bad actors if we have one-off individuals who are personally abusing our systems. Based on the telemetry ID included with each contact form submission, we’re able to pass a unique visitor ID to Hubspot. As a result, if Sales reps or BDRs are repeatedly seeing trolling or spam from a user, they can set a rule to block that individual going forward.
This is as simple as a single CURL request or, with <5 minutes of additional configuration, a quick input into a Retool GUI like this:
While spam form signups are a particularly annoying and visible form of spam across the org – since they typically impact engineering, marketing, sales, and sometimes other teams like technical support or customer success – spam takes many forms. This same type of logic and technique can be used to protect other resources, like help ticket submissions or authentication flows.
Or – if you use fingerprinting on page load, rather than on submit, it can also be used to prevent having bots or other invalid traffic skew visitor and conversion data on your contact forms, or to protect ads from click fraud. If you’re interested in learning more, you can read more about how browser fingerprinting works or explore Stytch’s Device Fingerprinting docs.
There are also a wide range of other ways to submit spam form signups; if you have other ideas you would suggest to our team or other use cases we should consider, consider dropping into our Developer Slack to let us know! Alternately, feel free to fill out our Contact Us form to get in touch; after all, we’ll know right away if you’re a real person or a bot.
Thanks for reading, and good luck fighting spam.