Protection of forms from "invisible" Google reCAPTCHA v3 spam without losing PageSpeed ​​Insight points

From time to time there was a question about protection from bots of various forms on the site: registration, authorization, subscription to newsletters, feedback, commenting, etc.



Standard CAPTCHA is useless, bots go through it "at once", and creates problems for users.



The best solution is to use Google reCAPTCHA v2 or v3. Both versions of Google reCAPTCHA are great options. This is the best that is now available on the market from clear and reliable solutions, and also free.



The main problem with both versions is that when connected, the PageSpeed ​​Insight scores are significantly reduced by 20-30.



ReCAPTCHA v2 example - requires guessing pictures



Example reCAPTCHA v3 - does not require actions from the user, analyzes his behavior in the background



An important point for me is not to create problems for real users, because I myself am not a big fan of guessing vehicles in reCAPTCHA v2, so my choice is v3.



So there are two Google reCAPTCHA v3 problems that need to be addressed:



  • hanging logo in the lower right corner;
  • loss of 20-30 points on Google PageSpeed ​​Insight.


Hanging logo



Google allows you to remove the logo by hiding it through CSS in its license agreement.



.grecaptcha-badge {
	visibility: hidden;
}


Instead, write “Anti-spam reCAPTCHA Privacy and Terms of Service” under each form with links to the relevant Google pages.





Loss of points on Google PageSpeed ​​Insight



When connecting a javascript file from reCAPTCHA v3, the scores on Google PageSpeed ​​Insight are greatly reduced. This was critical for me. I think this is due to the analysis of user behavior (a similar decrease occurs when using the web visor in Yandex.Metrica).



On well-optimized resources, you can lose 20-30 points. Therefore, you can use it on separate pages where speed is not important (for example, contacts) without modifications. For use on the entire site (for example, to protect the end-to-end login form or newsletter subscription), it is advisable to make a modification.



I came up with an option to initialize reCAPTCHA v3 by clicking on the form fields. By default, I do not load the javascript file from reCAPTCHA v3, and only if the user places the cursor on one of the form fields do I load it. Most likely, this method reduces the accuracy of determining real users, but there were no problems. This accuracy is enough for my tasks.



He began to use this technique first on 1C-Bitrix web forms, then for end-to-end authorization and subscription forms on sites without Bitrix.



In view of the fact that 1C-Bitrix is ​​a public CMS, I will tell you in general terms using its example - about the methodology and possible use case. More fine tuning can be done to suit your needs.



Using Google reCAPTCHA v3 in 1C-Bitrix web forms



1. We call the form using the standard bitrix: form component and make 2 additions:



  • Replace the button type = submit with the usual button type = button
  • add hidden field name = g_recaptcha_response






2. Add reCAPTCHA initialization when clicking on form fields to the javascript file of the site or component (in this example, I assume that you are using jQuery):



$('body').on('click','form input, form textarea', function() {
	if (typeof(grecaptcha) == 'undefined') {
		var grecaptcha_s = document.createElement('script');
		grecaptcha_s.src = 'https://www.google.com/recaptcha/api.js?render=<PUBLIC_KEY>';

		var grecaptcha_h = document.getElementsByTagName('script')[0];
	grecaptcha_h.parentNode.insertBefore(grecaptcha_s,grecaptcha_h);
	}
});


3. Add tracking of the click on the button button in the form. Further inside, we use the example described in the Google documentation. It fills in the g_recaptcha_response field, which we will use in the last step to validate the user.



$('body').on('click','form button[name="web_form_submit"]', function() {
	grecaptcha.ready(function() {
		grecaptcha.execute('<PUBLIC_KEY>',{action: 'feedback'}).then(
			function(token) {
				$('form input[name="g_recaptcha_response"]').val(token);

				var form_obj = $('form');
				var event_obj = form_obj.get(0);

				BX.fireEvent(event_obj,'submit');	
				event_obj.submit();
			}
		);
	});
});


4. Tracking the event onBeforeResultAdd in init.php



Before submitting the results of the form, make an appeal to the Google server with your <PRIVATE_KEY>, and the value from the hidden field g_recaptcha_response from the form.



In response, we get the points of this user:



  • 1 this is definitely a person
  • 0 exactly a robot
  • More than 0.5 can be considered human


AddEventHandler("form","onBeforeResultAdd","onBeforeResultAddHandler");

function onBeforeResultAddHandler($WEB_FORM_ID,$arFields,$arrVALUES)
{
	global $APPLICATION;

	$g_recaptcha_response = $arrVALUES["g_recaptcha_response"];
	if (!empty($g_recaptcha_response))
	{
		$response = json_decode(file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=<PRIVATE_KEY>&response=".$g_recaptcha_response."&remoteip=".$_SERVER["REMOTE_ADDR"]),true);
			

		$g_recaptcha_response_check = false;

		if (($response["success"] and $response["score"] >= 0.5 and $response["action"] == 'feedback']))
		{
			$g_recaptcha_response_check = true;
		}

		if (!$g_recaptcha_response_check)
		{
			$APPLICATION->ThrowException('   Google reCAPTCHA v3.</a>');
		}
	}
	else
	{
		$APPLICATION->ThrowException('   Google reCAPTCHA v3.');
	}
}


Finally



This technique can be used on any sites and forms, regardless of the CMS. I have provided general working methods that can be applied in your project.



You can do the same with Google reCAPTCHA v2, initialize by clicking on the form and ask the user to check the box "I'm not a robot" and guess the pictures, if necessary. In this case, it will also save PageSpeed ​​Insight points and give the user a tool (select pictures) to prove that they are not a robot. But as I said above, the most important thing for me is not to create obstacles for the user.



All Articles