Recaptcha: Unobtrusive ReCaptcha V3 `timeout-or-duplicate`

Created on 16 Apr 2019  路  11Comments  路  Source: google/recaptcha

When using V3, the docs suggest that you can perform a grecaptcha.execute on page load.

  1. Call grecaptcha.execute on an action or when the page loads (see https://developers.google.com/recaptcha/docs/v3#site-verify-response)

I am finding though, that sporadically, some site verify responses are returning timeout-or-duplicate when I do a server-side site verification.

I am assuming that as I am executing grecaptcha.execute on page load to capture the token, which I submit with my form posts, by the time the user has completed the form I believe the token is expiring.

When using the grecaptch.render API, it allows you to pass an callback for expired-callback to reset a grecaptcha.

Does the execute method in V3 support such a callback?

For my form posts, should I instead be triggering grecaptcha.execute on form submit instead?

Note: I've checked my running application, and I cannot find any instances of double submitting of tokens

Most helpful comment

Agree. The documents (really) sucks. If you read the document like APIs from Stripe, and then compare to this. You will see the difference.

People at Google don't care that much I think. Big company problem.

All 11 comments

Have exact same issue. Token appears to expire after a few minutes. I execute on page load and populate a hidden form field. By the time the user submits the form the token is expired.

Neither the error code nor the expiration is documented. Some have suggested posting the token back to server immediately upon page load, verifying it with Google, and then cross referencing it later.

Thanks for the heads-up - the documentation is now (more) up to date here: https://developers.google.com/recaptcha/docs/verify

In general prefer to run grecaptcha.execute at the time of the action for better risk analysis.

Dunno, but the current documentation says

Note: You can execute reCAPTCHA as many times as you'd like with different actions on the same page.

which led me to believe it's a good practice to invoke grecaptcha.execute on page load and also when the user does certain things like clicking a button. However, invoking it sufficient times while on the same page, doesn't seem to be a good practice, because regardless very often I receive the timeout-or-duplicate error.

Speaking of the documentation: It would be very nice to have a good (and bad) practices section and more examples. I'm still stuck with the above error.

Agree. The documents (really) sucks. If you read the document like APIs from Stripe, and then compare to this. You will see the difference.

People at Google don't care that much I think. Big company problem.

Shoot, i got this error often nowadays.

I came up with a solution:

    <script>
        grecaptcha.ready(function () {
            grecaptcha.execute('GOOGLE CLIENT KEY', {action: 'contact'}).then(function(token) {
                $('#email_form').prepend('<input id="recaptcha_token" type="hidden" name="token" value="' + token + '">');
                console.log("recaptcha_token set on email_form >> token = " + token);
            });
            setInterval(function () {
                grecaptcha.execute('GOOGLE CLIENT KEY', { action: 'contact' }).then(function (token) {
                    if ($("#recaptcha_token").length) {
                        console.log("set new token to existing input >> token = " + token);
                        $("#recaptcha_token").val(token);
                    } else {
                        console.error("recaptcha_token does not exist on email_form");
                    }
                });
            }, 60000);
        });      
    </script>

I set the interval to one minute because I have no idea how long it takes for the timeout-or-duplicate error to occur.

How about just adding the token when submitting the form? So you don't need to refresh it all the time.

<script>
  grecaptcha.ready(function() {
      document.getElementById('contactform').addEventListener("submit", function(event) {

        event.preventDefault();

        grecaptcha.execute('mykey', {action: 'homepage'}).then(function(token) {
           document.getElementById("googletoken").value= token; 
           document.getElementById('contactform').submit();
        });        
      }, false);

  });
</script>

@iwasherefirst2
The solution isn't perfect. Because, when we request the token just before the send. The form needs waiting few seconds to receive token and send with the data.

@iwasherefirst2
The solution isn't perfect. Because, when we request the token just before the send. The form needs waiting few seconds to receive token and send with the data.

Yes, good point.

@iwasherefirst2
The solution isn't perfect. Because, when we request the token just before the send. The form needs waiting few seconds to receive token and send with the data.

You can wrap the execute method in a Promise and continue the execution after receive the token:

function getToken() {
      return new Promise(function (resolve, reject) {
                            try {
                                grecaptcha.ready(function () {
                                    grecaptcha.execute('your_key', { action: 'your_action' }).then(function (token) {
                                        resolve(token);
                                    });
                                });
                            } catch (e) {
                                resolve('');
                            }
                        });
}

getToken().then(token =>
{
   //Send form to server
})

I call this method just before send the form to the server, but ocassionally still have the "timeout-or-duplicate" error.``

The recaptcha instance grecaptcha has a reset() function.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DanielaValero picture DanielaValero  路  15Comments

luckyvs1 picture luckyvs1  路  9Comments

renorram picture renorram  路  5Comments

ryanbr picture ryanbr  路  14Comments

Chaython picture Chaython  路  5Comments