Just in case you've not tried it, a bot-catching honeypot field on the form might help, with the substantial benefit that it's completely invisible to real human visitors. No test or questions to prove that they're human. I've found it surprisingly -- but to be fair, not 100% -- successful. If you've already tried it, then you have to go to a bigger, more intrusive technique, and you can stop reading this post at this point.
I add a field to the form like the following, give the list element class ("noDisplay" in this case) CSS display: none, and apply the formit "empty" validator to the field.
<li class="noDisplay">
<label for="email2">Leave this entry empty</label>
<input type="text" name="email2" id="email2" value="[[!+fi.email2]]" />
</li>
Notes:
- Most of the lesser-intelligent bots will try to fill in every field, including this one, thus trapping them with a validation error for this field that's supposed to be empty
- It's better to use CSS to hide the field and its label. Making the field's type "hidden" is just too easy for the bot to pick-up
- A "semi-smart" bot might look for class names that hide fields, you could change the class on the <li> to something less obvious
- Using the same reasoning, I tend to use real-sounding field names for the honeypot field, to perhaps trick bots that have a list of common honeypot field names to skip
- Using display: none on the list element effectively hides the field label and input from both sighted human users and human users using most screen readers, which tend to ignore DOM elements and descendants marked display: none.
- In the rare case where a real human visitor is browsing sans-CSS, the form element's label will tell them to skip the field
Limitations:
- If a bot's smart enough to render the page and apply CSS, and only enter field entries that are visible, this technique won't work
- If a bot farm has been "taught" how to fill out your specific form by a low-paid human, this technique won't help