I agree that "invisible" recaptcha documentation is not comprehensive enough. I had to spend some time digging thru code example and documentations of "visible" recaptcha before understanding how to work with this.
Let talk about the recaptcha API first:
grecaptcha.render(htmlEl, options, inherit)
is JS API method of rendering the captcha HTML on the page. By default recaptcha script will try to find any element with class="g-recaptcha
and try to render immediately, but this behavior can be overridden by appending ?render=explicit
query param to recaptcha script src url. You also may want to render the recaptcha html on demand using this api when your recaptcha .g-recaptcha
element gets attached to DOM at a point later than when script was loaded. This api returns an ID value that can be passed to other api methods, but if not passed, those api's lookup and reference first repcaptcha on page.
grecaptcha.getResponse(optional_id)
returns the token. If token is empty string, it means user has not been validated yet i.e. user hasn't completed the captcha challenge.
grecaptcha.execute(optional_id)
api triggers the recaptcha challenge on-demand programmatically. This api is only applicable to "invisible" recaptcha. Visible recaptcha challenges are triggered when user clicks the recaptcha module.
grecaptcha.reset(optional_id)
will reset a challenge i.e. it must be done each time server fails to validate the token with recaptcha api server (because tokens are one time use), but depending on your implementation, you may decide to reset any time.
Now, lets talk about data-callback:
data-callback
is an attribute where you can pass a name of global namespaced function, i.e. some function which is accessible as window['nameOfFunction']. This callback will get called each time user is successfully validated with a token value that you will eventually be passing to server. This is same token that is returned by grecaptcha.getResponse()
so technically you do not need this function at all. But it can serve as callback to let you know user has passed verification in case you need to update UI or something.
If for some reason you do not want this callback to be accessible from window namespace, you can pass this method in options object with callback
key to grecaptcha.render()
. NOTE: options.callback
can take a string value which is equivalent to passing data-callback
attribute in HTML, i.e. is must be a function in window namespace. But options.callback
can take a "function" value as well.
Now some sample code:
HTML
<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=onScriptLoad" async defer></script>
JS
window.onScriptLoad = function () {
// this callback will be called by recaptcah/api.js once its loaded. If we used
// render=explicit as param in script src, then we can explicitly render reCaptcha at this point
// element to "render" invisible captcha in
var htmlEl = document.querySelector('.g-recaptcha');
// option to captcha
var captchaOptions = {
sitekey: '6Lck',
size: 'invisible',
// tell reCaptcha which callback to notify when user is successfully verified.
// if this value is string, then it must be name of function accessible via window['nameOfFunc'],
// and passing string is equivalent to specifying data-callback='nameOfFunc', but it can be
// reference to an actual function
callback: window.onUserVerified
};
// Only for "invisible" type. if true, will read value from html-element's data-* attribute if its not passed via captchaOptions
var inheritFromDataAttr = true;
// now render
recaptchaId = window.grecaptcha.render(htmlEl, captchaOptions, inheritFromDataAttr);
};
// this is assigned from "data-callback" or render()'s "options.callback"
window.onUserVerified = function (token) {
alert('User Is verified');
console.log('token=', token);
};
// click handler for form's submit button
function onSubmitBtnClick () {
var token = window.grecaptcha.getResponse(recaptchaId);
// if no token, mean user is not validated yet
if (!token) {
// trigger validation
window.grecaptcha.execute(recaptchaId);
return;
}
var xhrData = {
'g-recaptcha-response': token
// more ajax body/data here
};
// proceed with appending more ajax call data to xhrData and then rest of ajax call process
// var xhr = new XMLHttpRequest();
// ... ... .... ... ...
}