When implement an invisible recaptcha following the method described by Sanford Whiteman here, the
var recaptchaResponse = grecaptcha.getResponse();
returns an empty response, and the validation fails.
this is the complete code used:
In the <head>
<meta class="mktoBoolean" id="GoogleRecaptcha" mktoName="Google Recaptcha" default="false" true_value="true" false_value="false" false_value_name="Deactivated" true_value_name="Activated">
in the <body>
<div id="InvisibleRecaptcha" class="g-recaptcha" data-sitekey="${GoogleRecaptchaSiteKey}" data-size="invisible" data-callback="donothing"></div>
in the forms whenready:
var formEl = form.getFormElem()[0],
emailEl = formEl.querySelector('#Email'),
submitEl = formEl.querySelector('BUTTON[type="submit"]'),
recaptchaEl = document.querySelector('.g-recaptcha’),
formElId = form.getId();
if (${GoogleRecaptcha}) {
form.submittable(false);
// force resize reCAPTCHA frame
recaptchaEl.querySelector('IFRAME').setAttribute('height','140');
// move reCAPTCHA inside form container
formEl.appendChild(recaptchaEl);
}
form.onValidate(function(builtInValidation){
//code to handle the recaptcha
if(${GoogleRecaptcha}) {
if (!builtInValidation) return;
//calling the recaptcha
var recaptchaResponse = grecaptcha.getResponse();
if (!recaptchaResponse) {
recaptchaEl.classList.add('mktoInvalid');
} else {
recaptchaEl.classList.remove('mktoInvalid');
form.addHiddenFields({
lastRecaptchaUserInput: recaptchaResponse,
lastRecaptchaEnabledFormID: formElId
});
form.submittable(true);
}
}
});
Any idea about what I am missing?
The same code works perfectly well with a visible (v2) recaptcha.
-Greg
What's the URL?
The invisible form doesn't have an internal IFRAME (and doesn't need to be moved), so you need to take out these lines:
recaptchaEl.querySelector('IFRAME').setAttribute('height','140');
formEl.appendChild(recaptchaEl);
Hi Sanford,
Thx
I commented the 2 lines, but it is still not working. I also added an onsubmit function, as per the doc, it seems mandatory, to no avail
-Greg
OK, now onto the next bug(s).
You don't want to call grecaptcha.render() in the onValidate, as it's already rendered (that's throwing an error that's ending form submission).
Also remove that onSubmit, it's not doing anything.
Hi Greg,
You'll need to use...
grecaptcha.execute(reCAPTCHA);
...when someone tries to submit the form. If you don't programmatically "execute" the Invisible reCAPTCHA...
grecaptcha.getResponse();
...will always return an empty response. (Invisible) reCAPTCHA uses a callback that you should use to handle completion of the captcha after executing it. Also, if you want to support multiple forms on the same page, you'll have to create multiple instances of reCAPTCHA (for each form) and should thus not include the following HTML as described in the documentation.
<div class="g-recaptcha"
data-sitekey="your_site_key"
data-callback="onSubmit"
data-size="invisible">
</div>
Instead, just include the reCAPTCHA script on your page and embed the forms as you would do normally.
<script src='https://www.google.com/recaptcha/api.js?render=explicit'></script>
<script src="https://app-lon07.marketo.com/js/forms2/js/forms2.min.js"></script>
<form id="mktoForm_1"></form>
<script>MktoForms2.loadForm("//app-lon07.marketo.com", "123-ABC-456", 1);</script>
Then use the following script to use it for all forms. If needed you can also slightly adjust it to only use reCAPTCHA for one or a couple of forms.
/**
* Use Google's reCAPTCHA to protect against spam and other types of automated abuse.
* @param {Object} mktoForm
* @param {Object} options
* @param {String} options.size 'invisible', 'compact', 'normal'
* @param {String} options.siteKey Public reCAPTCHA sitekey
* @param {String} options.fieldName Marketo SOAP name for field that holds response value
* @param {String} options.errorMessage Error message depending on choosen `size`
* @return {Void}
*/
function useReCAPTCHA(mktoForm) {
var options =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (
!Object.prototype.hasOwnProperty.call(options, "fieldName") ||
!Object.prototype.hasOwnProperty.call(options, "sitekey") ||
!Object.prototype.hasOwnProperty.call(options, "errorMessage") ||
!Object.prototype.hasOwnProperty.call(options, "size")
) {
if (console) {
console.warn("Parameters for reCAPTCHA are missing.");
}
return;
}
var formEl = mktoForm.getFormElem()[0];
var formId = mktoForm.getId();
var reCAPTCHAEl = document.createElement("div");
reCAPTCHAEl.setAttribute("id", "reCAPTCHA_" + formId);
formEl.parentNode.insertBefore(reCAPTCHAEl, formEl.nextSibling);
var reCAPTCHA = grecaptcha.render("reCAPTCHA_" + formId, {
size: options.size,
sitekey: options.sitekey,
callback: function callback() {
mktoForm.submittable(true);
mktoForm.submit();
},
"error-callback": function errorCallback() {
mktoForm.showErrorMessage(options.errorMessage);
}
});
mktoForm.onValidate(function(isValid) {
if (!isValid || !mktoForm.submittable()) {
return;
}
var reCAPTCHAResponse = grecaptcha.getResponse(reCAPTCHA);
if (!reCAPTCHAResponse) {
if (options.size === 'invisible') {
grecaptcha.execute(reCAPTCHA);
} else {
mktoForm.showErrorMessage(options.errorMessage);
}
mktoForm.submittable(false);
} else {
var hiddenFields = {};
hiddenFields[options.fieldName] = reCAPTCHAResponse;
mktoForm.addHiddenFields(hiddenFields);
}
});
}
MktoForms2.whenReady(function(mktoForm) {
useReCAPTCHA(mktoForm, {
size: "invisible",
sitekey: "KEY",
fieldName: "lastreCAPTCHAResponse",
errorMessage: "Sorry, something wen't wrong"
});
});
Please note that I haven't tested it fully (yet) but feel free to test if it works for you. It did for me in my tests.
Best regards,
Markus