Using reCaptcha v2 for your forms

Updated on 11-September-2020 at 8:57 PM

Business Catalyst End of life announcement - find out more details.

This article will show you how to make sure you are using the newest bot-protection module on your forms.

Do note this article only refers to regular Web forms & Campaign subscribe forms, for the Comment forms for example, there is no action required.

You only need to take action if your site contains forms that submit to FormProcessV2.aspx or CampaignProcess.aspx.

Add reCaptcha v2 to your webforms

  1. Go to Site Manager->Web forms and select your form
  2. from the Misc tab, click on Recaptcha V2
  3. Recaptcha V2 is now inserted into your form, as you can see in the webform preview on the right
  4. Insert the webform onto the page you want

Add reCaptcha V2 to existing webforms already added to site pages

Go to every page where you have added webforms, and update them. This can be done in two ways:

  • completely delete the form's HTML code from the page and reinsert the form
  • add the reCaptcha control on the existing markup:
    1. add this inside the form, where you want the reCaptcha control to be rendered:
      {module_recaptcha version="2"}
    2. Add the JavaScript form validation code into page. In JS validation code section, add these lines to the checkWholeForm<form_id>(theForm) function definition:
      if (theForm['g-recaptcha-response']) why += reCaptchaV2IsInvalid(theForm, "Please prove you're not a robot");

Replace the old bot protection modules with reCapcha v2 on webforms

  1. Go to Site Manager->Web Forms and select your webform
  2. Go to the Misc tab
  3. Remove the old bot protection modules (Image verification or Recaptcha):
    remove.png
  4. Insert the new Recaptcha V2 instead:
    remove.png
  5. Save the form
  6. Now you need to go to every page this form is inserted into and update it. The form update can be done in two ways:
    • completely delete the form's HTML code from the page and reinsert the form
    • replace the old recaptcha modules with the new one. To do this simply replace
      {module_recaptcha} or {module_captchav2}
      with
      {module_recaptcha version="2"}

Replace the old bot protection modules with reCapcha v2 on campaign subscribe forms

You need to edit every page the campaign subscribe form is inserted into, and update it. The form update can be done in two ways:

  • completely delete the form's HTML code from the page and reinsert the form
  • replace the old recaptcha modules with the new one. To do this simply replace
    {module_recaptcha} or {module_captchav2}
    with
    {module_recaptcha version="2"}

Add reCapcha v2 on campaign subscribe forms

Option A: re-insert the form(s)

 Edit every page the campaign subscribe form is inserted into completely delete the form's HTML code from the page and reinsert the form

Option B: manually update existing form(s) to add reCaptchav2 code

You need to edit every page the campaign subscribe form is inserted into and update it. There are two steps to the process:

  1. Add the recaptcha module in the code. To do this, simply add the reCaptchav2 module at the end of the form:
    {module_recaptcha version="2"}
  2. Add the JavaScript form validation code into page. In JS validation code section, add these lines to the checkWholeForm<form_id>(theForm) function definition:
    if (theForm.CaptchaV2) why += captchaIsInvalid(theForm, "Enter Word Verification in box below", "Please enter the correct Word Verification as seen in the image");
    if (theForm['g-recaptcha-response']) why += reCaptchaV2IsInvalid(theForm, "Please prove you're not a robot");

Ajax forms

If you submit these forms with ajax, you need to take an extra step in your javascript code, that is to reinitialize the reCaptcha controls after a form was submitted.

This can be achieved by adding the following line of code in your post-submit success and error handlers, otherwise a subsequent submit action will fail to validate:

reCaptchaV2Manager.reloadControls();

Please note that the page that contains the forms should load the /CatalystScripts/ValidationFunctions.js script (included automatically when adding the form to page).

Look and feel

It is possible that the reCaptcha control does not match your website design or theme. If this is the case, you can still customize the way the reCaptcha control is rendered on the page, using the following parameters:

  • theme can be light or dark
  • size can be normal or compact (invisible is not supported)

Here is what the reCaptcha will look like when you customize the theme and size parameters:

  • Light theme, normal size:
    {module_recaptcha theme="light" size="normal"}
  • Light theme, compact size:
    {module_recaptcha theme="light" size="compact"}
  • Dark theme, normal size:
    {module_recaptcha theme="dark" size="normal"}
  • Dark theme, compact size:
    {module_recaptcha theme="dark" size="compact"}

More information can be found in the module_recaptcha liquid tag documentation page.

Custom Ajax and non-standard forms

It is also possible that certain websites have completely customized the way information is submitted to the BC webforms handler.

This can be done by adding a manually written form html with custom styling and behavior, or even no HTML at all, just with some scripting that submits some values (predefined, generated or aggregated from various sources) to the webform handler.

Even for this kind of webform, it is possible to add reCaptcha and make them more secure, but the process requires some manual work. You will need to take the following steps:

  1. Load the reCaptcha script from Google
    <script src="https://www.google.com/recaptcha/api.js?render=explicit"></script>
  2. Initialize a reCaptcha instance

    For this, you will need to have an insertion point for the reCaptcha widget somewhere in the DOM. Also, make sure you initialize the reCaptcha widget using the BC reCaptcha site key, which is 6LcGXxsUAAAAALhWpOesJevjsD2KnvmZbTZADnIJ.

    Example using jQuery:

    // the id of the DOM node inside which 
    // the reCaptcha control should be rendered
    var containerId = "recaptcha-container";
    
    // possible values: dark, light
    var theme = 'light';
    
    // possible values: normal, compact
    var size = 'normal';
    
    // this will be a reference to the reCaptch control
    var reCaptchaControl;
    
    // when reCaptcha is ready to use, initialize the control
    grecaptcha.ready(function() {
        reCaptchaControl = grecaptcha.render(containerId, {
            sitekey : '6LcGXxsUAAAAALhWpOesJevjsD2KnvmZbTZADnIJ',
            theme   : theme,
            size    : size,
        });
    	// at this point the reCaptcha control should be rendered on the page
    });
  3. Load a reCaptcha token from BC

    This step is also needed for increased security. The BC webform handler will reject any request that does not contain a previously generated unique token. This token needs to be refreshed after each webform submission, as each token can only be used once.

    Here is a small example of such a request, done using jQuery:

    // this variable will hold the reCaptcha token needed
    // when submitting the webform
    var reCaptchaToken;
    
    function loadReCaptchaToken() {
    	var tokenUrl = '/CaptchaHandler.ashx?RegenerateV2=true&count=1&rand=' 
    			+ Math.random();
    	$.ajax(tokenUrl)
    		.done(function(token){
                reCaptchaToken = token;
            });
    }
    loadReCaptchaToken();
  4. Submit the webform

    When submitting the webform, also include the reCaptcha token from step 3, and the reCaptcha response. It would also be nice if you could prompt the user to prove they are not a robot (if they did not click the reCaptcha checkbox yet).

    VERY IMPORTANT: if you need to re-use the webform and submit new values without refreshing the page, you need to re-initialize the reCaptcha control, and fetch a fresh new reCaptcha token.

    The example below continues the ones above. For simplicity, using jQuery.

    // this is your webform url; it can be obtained by inspecting 
    // the generated HTML when inserting the form into a page with
    // the JSON query parameter appended to it.
    var webFormUrl = '/FormProcessv2.aspx?WebFormID=...' + '&JSON=1';
    
    // here you would normally collect the data to be submitted
    var payload = {};
    
    // the reCaptcha token needs to also be sent
    payload['bc-recaptcha-token'] = token; // see step 3
    
    // we need to collect the reCaptcha response and add it to the payload
    payload['g-recaptcha-response'] = $('#g-recaptcha-response').val();
    
    // submit the data
    $.post(webFormUrl, payload)
        .done(function(){
        	// your success handler
        })
        .fail(function(){
    		// your error handler
        })
    	.always(function() {
    		// here we refresh the reCaptcha token
    		loadReCaptchaToken();
    		// also, we reset the reCaptcha control
    		grecaptcha.reset(reCaptchaControl);
    	});

Other things to consider
Please note that the output that the BC webform handler produces needs to be pre-processed, because in some situations it will return invalid JSON (issue is queued for fixing). Also, errors are not returned as JSON, so the response needs to be scanned for errors.

Here is an example of handling these issues, using jQuery again, for simplicity:

// Bc webforms handler quirks
$.ajaxPrefilter(function(options, config, jqXHR) {
	var url = options.url.toLowerCase();
    if (url.indexOf('/formprocessv2.aspx') === -1 
		|| url.indexOf('json=1') === -1) 
	{
        return;
    }
    options.converters["text json"] = function(data) {
        return $.parseJSON(data.replace(/True/g, 'true')
			.replace(/False/g, 'false'));
    }
    var deferred = $.Deferred();

    jqXHR.then(
        function(data, status, jqXHR) {
            if (typeof data === 'string' && data.indexOf('ERROR:') !== -1){
                var error = data
                    .replace(/[\n\r]+/g, '')
                    .replace(/^.*ERROR:/, '')
                    .replace(/<.*$/, '')
                    .trim()
                deferred.reject(error);
            } 
			else if(typeof data === 'object' 
					&& typeof data.SystemMessage === 'object' 
					&& !data.SystemMessage.success) 
			{
                deferred.reject(data.SystemMessage.message);
            } 
			else 
			{
                deferred.resolve(data, status, jqXHR);
            }
        }, 
        function(jqXHR, statusText, errorThrown) {
            deferred.reject(errorThrown);
        }
    );
    return deferred.promise(jqXHR);
});

Note: the above code blocks are provided as examples, and should be treated as such. Always properly test your code before publishing any changes that might break your webform.