
3 Tricks to Help Prevent SPAM in Your Contact Forms
TLDR;
If your contact form is getting flooded with spam, here are 3 DIY techniques which can help to keep it under control:
- Use a basic math captcha to stop the simplest bots
- Add a hidden honeypot field that real users won't see but bots might fill out
- Check if JavaScript is enabled (makes it a bit more likely the page is being viewed in an actual web browser)
Note that these aren't foolproof, especially in the age of AI and browser based agents. You could also consider tracking heuristics like the time it takes to fill out the form and blocking suspicious submissions (e.g. if it's filled out too quickly). If you need something more robust than a DIY approach, Google's reCAPTCHA is a solid choice since it uses machine learning to continually improve its accuracy.
1. Add a Simple Math Captcha
One of the easiest anti-spam measures is a simple math captcha. No need for weird squiggly letters or third-party services. We just generate a basic math question like "3 plus 7" and ask the user to solve it before submitting.
Here’s how we generate the question server-side in our controller:
// ContactController.php
public function show()
{
$num1 = rand(1, 10);
$num2 = rand(1, 20);
session(['captcha_question' => "$num1 plus $num2", 'captcha_answer' => $num1 + $num2]);
return view('contact');
}
And in the Blade view, we show the question and expect an answer:
<label for="captcha">Captcha</label>
<input type="text" name="captcha" id="captcha" required>
<p>Please solve: {{ session('captcha_question') }}</p>
Then in the form request, we compare the user’s answer with the one stored in the session:
'captcha' => ['required', 'numeric', function ($attribute, $value, $fail) {
if ($value != session('captcha_answer')) {
$fail('The captcha answer is incorrect.');
}
}],
Finally in order for the user to see an error if they're a little bit rusty with their math, or if there are any other form errors, we can add a simple loop to the top of the page:
@if($errors->any())
<div class="mb-6 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
<ul class="list-disc pl-5">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
2. Add a Honeypot Field
A honeypot field is a hidden input field that normal users never see, but bots sometimes like to blindly fill out. If this field contains any data, we know it’s a bot submission and we can safely ignore it.
Here’s the honeypot field added to our Blade form:
<div class="hidden">
<label for="honeypot">Leave this empty</label>
<input type="text" name="honeypot" id="honeypot">
</div>
And in our validation rules, we simply check that it remains empty:
'honeypot' => ['nullable', function ($attribute, $value, $fail) {
if (!empty($value)) {
$fail('The form submission is invalid.');
}
}],
3. Use a JavaScript-Based Checksum
This one’s a bit sneakier. Some bots don’t load or execute JavaScript. We can add a hidden field with a default value (like 1
) that gets changed to 2
with JavaScript on page load. If the value is wrong, we reject the form.
Here’s the hidden input:
<div class="hidden">
<label for="checksum">Checksum</label>
<input type="text" name="checksum" id="checksum" value="1">
</div>
Then we update it with JS when the DOM loads:
@section('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Change the checksum value to 2
document.getElementById('checksum').value = 2;
});
</script>
@endsection
In the validation rules, we check the value:
'checksum' => ['required', 'numeric', function ($attribute, $value, $fail) {
if ($value != 2) {
$fail('Something went wrong while trying to submit the form.');
}
}],
Wrap-Up
All three techniques are easy to add and don’t require external services or JavaScript frameworks. They work well together and catch different types of bot behaviour. None of them are perfect on their own, but combined they make it a bit harder for automated spam to get through. And if you need more advanced protection beyond the DIY approach, there's always tools like Google reCAPTCHA that can help as well.