Simple and flexible spam protection solution for Rails applications.
Invisible Captcha provides different techniques to protect your application against spambots.
The main protection is a solution based on the
honeypot principle, which provides a better user experience since there are no extra steps for real users, only for the bots.
Essentially, the strategy consists on adding an input field
- shouldn't be visible by the real users
- should be left empty by the real users
- will most likely be filled by spam bots
It also comes with a time-sensitive
Invisible Captcha is tested against Rails
>= 3.2 and Ruby
Add this line to your Gemfile and then execute
<%= form_for(@topic) do |f| %> <%= f.invisible_captcha :subtitle %> <!-- or --> <%= invisible_captcha :subtitle, :topic %> <% end %>
class TopicsController < ApplicationController invisible_captcha only: [:create, :update], honeypot: :subtitle end
This method will act as a
before_action that triggers when spam is detected (honeypot field has some value). By default, it responds with no content (only headers:
head(200)). This is a good default, since the bot will surely read the response code and will think that it has achieved to submit the form properly. But, anyway, you can define your own callback by passing a method to the
class TopicsController < ApplicationController invisible_captcha only: [:create, :update], on_spam: :your_spam_callback_method private def your_spam_callback_method redirect_to root_path end end
Note that it is not mandatory to specify a
honeypot attribute (neither in the view nor in the controller). In this case, the engine will take a random field from
InvisibleCaptcha.honeypots. So, if you're integrating it following this path, in your form:
<%= form_tag(new_contact_path) do |f| %> <%= invisible_captcha %> <% end %>
In your controller:
invisible_captcha only: [:new_contact]
invisible_captcha sends all messages to
flash[:error]. For messages to appear on your pages, add
<%= flash[:error] %> to
app/views/layouts/application.html.erb (somewhere near the top of your
You can place
<%= flash[:error] %> next to
:notice message types, if you have them in your
Options and customization
This section contains a description of all plugin options and customizations.
You can customize:
sentence_for_humans: text for real users if input field was visible. By default, it uses I18n (see below).
honeypots: collection of default honeypots. Used by the view helper, called with no args, to generate a random honeypot field name. By default, a random collection is already generated.
visual_honeypots: make honeypots visible, also useful to test/debug your implementation.
timestamp_threshold: fastest time (in seconds) to expect a human to submit the form (see original article by Yoav Aner outlining the idea). By default, 4 seconds. NOTE: It's recommended to deactivate the autocomplete feature to avoid false positives (
timestamp_enabled: option to disable the time threshold check at application level. Could be useful, for example, on some testing scenarios. By default, true.
timestamp_error_message: flash error message thrown when form submitted quicker than the
timestamp_thresholdvalue. It uses I18n by default.
injectable_styles: if enabled, you should call anywhere in your layout the following helper
<%= invisible_captcha_styles %>. This allows you to inject styles, for example, in
<head>. False by default, styles are injected inline with the honeypot.
To change these defaults, add the following to an initializer (recommended
InvisibleCaptcha.setup do |config| # config.honeypots << ['more', 'fake', 'attribute', 'names'] # config.visual_honeypots = false # config.timestamp_threshold = 4 # config.timestamp_enabled = true # config.injectable_styles = false # Leave these unset if you want to use I18n (see below) # config.sentence_for_humans = 'If you are a human, ignore this field' # config.timestamp_error_message = 'Sorry, that was too quick! Please resubmit.' end
Controller method options:
invisible_captcha method accepts some options:
only: apply to given controller actions.
except: exclude to given controller actions.
honeypot: name of custom honeypot.
scope: name of scope, ie: 'topic[subtitle]' -> 'topic' is the scope.
on_spam: custom callback to be called on spam detection.
timestamp_enabled: enable/disable this technique at action level.
on_timestamp_spam: custom callback to be called when form submitted too quickly. The default action redirects to
:backprinting a warning in
timestamp_threshold: custom threshold per controller/action. Overrides the global value for
View helpers options:
Using the view/form helper you can override some defaults for the given instance. Actually, it allows to change:
<%= form_for(@topic) do |f| %> <%= f.invisible_captcha :subtitle, sentence_for_humans: "hey! leave this input empty!" %> <% end %>
<%= form_for(@topic) do |f| %> <%= f.invisible_captcha :subtitle, visual_honeypots: true %> <% end %>
You can also pass html options to the input:
<%= invisible_captcha :subtitle, :topic, id: "your_id", class: "your_class" %>
invisible_captcha tries to use I18n when it's available by default. The keys it looks for are the following:
en: invisible_captcha: sentence_for_humans: "If you are human, ignore this field" timestamp_error_message: "Sorry, that was too quick! Please resubmit."
You can override the English ones in your i18n config files as well as add new ones for other locales.
If you intend to use I18n with
invisible_captcha, you must not set
timestamp_error_message to strings in the setup phase.
Testing your controllers
If you're encountering unexpected behaviour while testing controllers that use the
invisible_captcha action filter, you may want to disable timestamp check for the test environment. Add the following snippet to the
# Be sure to restart your server when you modify this file. InvisibleCaptcha.setup do |config| config.timestamp_enabled = !Rails.env.test? end
Another option is to wait for the timestamp check to be valid:
# Maybe in a before block InvisibleCaptcha.init! InvisibleCaptcha.timestamp_threshold = 1 # Before testing your controller action sleep InvisibleCaptcha.timestamp_threshold
Clone/fork this repository, start to hack on it and send a pull request.
Run the test suite:
$ bundle exec rspec
Run the test suite against all supported versions:
$ bundle exec appraisal install $ bundle exec appraisal rspec
Run specs against specific version:
$ bundle exec appraisal rails-5.2 rspec
Start a sample Rails app (source code) with
$ bundle exec rake web # PORT=4000 (default: 3000)
Copyright (c) Marc Anguera. Invisible Captcha is released under the MIT License.