Hi,
I'm experiencing inconsistencies with getting Google ReCAPTCHA v3 user score to populate in a hidden field when a form is submitted. The score is added correctly to the hidden field most of the time but is empty roughly 10-15% of the time (based on our lead submissions this month). I've followed the recommended Marketo implementation of recaptcha and will place the current implementation below. The implementation below is used on all of our pages that include Marketo forms, and I we have seen issues on all of them (not finding any trends that would lead me to believe it's a specific page-related issue). NOTE: We are NOT using Marketo for the validation process - this is built on Adobe Runtime, and as you can see is called inside the grecaptcha.execute function after the recaptchaFinger is returned (in .then()). Also, we only recently changed the captchaResponse field (the hidden field that is added with recaptcha score) to be readOnly, so this shouldn't be an issue.
If anyone has any thoughts or tips to resolve this it would be greatly appreciated! Thanks!
// if Marketo Forms function available, and document contains a marketo form
if (typeof MktoForms2 !== "undefined" && document.querySelectorAll("form[id^=\"mktoForm_\"]").length > 0) {
/* ======= START RECAPTCHA ======= */
// user config for recaptcha
var userConfig = {
apiKeys : {
recaptcha : <REMOVED_FOR_PRIVACY>
},
fields : {
recaptchaFinger : "lastRecaptchaUserInput"
},
actions : {
formSubmit : "form"
}
};
/* inject the reCAPTCHA library */
recaptchaLib = document.createElement("script");
recaptchaLib.src="https://www.google.com/recaptcha/api.js?render=" + userConfig.apiKeys.recaptcha + "&onload=grecaptchaListeners_ready";
document.head.appendChild(recaptchaLib);
MktoForms2.whenReady(function(mktoForm) {
var formEl = mktoForm.getFormElem()[0],
submitButtonEl = formEl.querySelector("button[type='submit']"),
moveEl = formEl.querySelector('.google-recaptcha-disclaimer');
// move disclaimer text row below submit button
[].forEach.call(formEl.querySelectorAll('.mktoForm > .mktoFormRow'), function(row) {
!row.contains(moveEl) || formEl.appendChild(row);
});
/* pending reCAPTCHA widget ready */
submitButtonEl.disabled = true;
/* pending reCAPTCHA verify */
mktoForm.submittable(false);
mktoForm.locked = false;
mktoForm.onValidate(function(native) {
if (!native) return;
// generate recaptcha token
grecaptcha.ready(function() {
grecaptcha.execute(userConfig.apiKeys.recaptcha, {
action: userConfig.actions.formSubmit
})
.then(function(recaptchaFinger) {
// =====================================
// Validation built on Adobe I/O Runtime
// =====================================
fetch('https://adobeioruntime.net/api/v1/web/23476-166aquamarinetoucan/default/validate.json?token='+ recaptchaFinger)
.then(function(response) { return response.json(); })
.then(function(data) { // access to response object here: score, success, challenge_ts, hostname
_satellite.logger.log('recieved captcha data')
var mktoFields = {};
// log errors, add errors to mktofield
if (data["error-codes"]) {
_satellite.logger.error('Error(s) validating recaptcha: ', data["error-codes"]);
_satellite.setVar('recaptchaError', data["error-codes"].join('|'));
mktoFields["recaptchaError"] = data["error-codes"].join('|');
}
if (mktoForm.locked == false) {
mktoForm.locked = true;
// set hidden fields with response data OR error
mktoFields["captchaResponse"] = data.score || data["error-codes"].join('|');
mktoForm.addHiddenFields(mktoFields);
_satellite.logger.log('hidden fields added: ', document.querySelector('input[name=captchaResponse]'))
document.querySelector('input[name=captchaResponse]').readOnly = true;
_satellite.logger.log('in recaptcha fetch making form submittable, submitting');
// submit the form
mktoForm.submittable(true);
mktoForm.submit();
_satellite.logger.log('FORM SUBMITTING (in recaptcha tag)', _satellite.getVar('recaptchaResponse'))
}
})
.catch(function(err) {
_satellite.logger.error('Error getting recaptcha response from Adobe Runtime API: ', err)
});
});
});
});
});
var recaptchaListeners = {
ready : function() {
MktoForms2.whenReady(function(mktoForm){
var formEl = mktoForm.getFormElem()[0],
submitButtonEl = formEl.querySelector("button[type='submit']");
submitButtonEl.disabled = false;
});
}
};
Object.keys(recaptchaListeners).forEach(function globalize(fnName){
window["grecaptchaListeners_" + fnName] = recaptchaListeners[fnName];
});
/* ======== END RECAPTCHA ======== */
}
... View more