41

I am using recaptcha v2

I am getting the following error occasionally (sometimes i don't get error and sometimes i do get it)

Uncaught ReferenceError: grecaptcha is not defined

It seems because of the internal http request. that takes some time to get another js recaptcha__en.js. Meanwhile actual rendering code of grecaptcha executes.

So what is the standard solution to avoid this issue.?

PS : of course i am looking for some solution other than setTimeout

yole
  • 92,896
  • 20
  • 260
  • 197
codeofnode
  • 18,169
  • 29
  • 85
  • 142

9 Answers9

35

Recaptcha has a onload callback that will run once recaptcha is loaded. Place your code inside that callback function.

https://developers.google.com/recaptcha/docs/display

<script>
    function onloadCallback() {
        /* Place your recaptcha rendering code here */
    }
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"></script>
Vigneswaran Marimuthu
  • 2,452
  • 13
  • 16
  • 3
    but i want to render the captcha challenge not on pageload. i want to render it after user enters into some bootstrap modal – codeofnode Apr 23 '15 at 11:53
  • @nodeofcode It is not page `onload`. This is provided by recaptcha. I have updated my answer with the example – Vigneswaran Marimuthu Apr 23 '15 at 11:53
  • i do get your point.. but how can i render captcha into block which doesn't exists – codeofnode Apr 23 '15 at 11:54
  • I didn't get what you meant by **but how can i render captcha into block which doesn't exists** ? – Vigneswaran Marimuthu Apr 23 '15 at 11:56
  • grecaptcha.render(, paramObj) .. here somedivid need to exists in DOM in order that captcha renders into this div. Now If i provide onload query param, then the callback executes right after the scripts get loaded, and at that time i don't have that somedivid. – codeofnode Apr 23 '15 at 11:58
  • I can get your point but i am not sure when `` will be available in DOM ? What you can do is, once you rendered ``, then you can inject captcha script with `onload` callback. – Vigneswaran Marimuthu Apr 23 '15 at 12:01
  • If you want to load grecaptcha on page load, then set a boolean inside the callback of `onload` and check against the boolean before rendering recaptcha. – Vigneswaran Marimuthu Apr 23 '15 at 12:02
  • Of course the wrapper www.google.com/recaptcha/api.js, get loaded. then my code get executed. But In this case, i have to inject recaptcha__en.js, not api.js. So the question in how do i inject second level code that is recaptcha__en.js? – codeofnode Apr 23 '15 at 12:38
  • @nodeofcode Why do you need to do that ? Any how `api.js` will do some pre-processing and will inject `recaptcha__en.js` (language specific code). – Vigneswaran Marimuthu Apr 24 '15 at 03:58
  • I had already injected api.js before this question was asked. Then i found that api.js does load recaptcha__en.js but only after its injection get resolved. – codeofnode Apr 24 '15 at 06:47
  • You can inject `recaptcha__en.js` yourself but i don't recommend it. Moreover, i think the content of `recaptcha__en.js` is dynamic. So, it is better to use `api.js` as suggested by them. – Vigneswaran Marimuthu Apr 24 '15 at 06:55
6

I have solved this by ordering the script in below manner

HTML

<div id="review_recaptcha"></div>

jQuery

<script type="text/javascript">
      var review_recaptcha_widget;
      var onloadCallback = function() {
        if($('#review_recaptcha').length) {
            review_recaptcha_widget = grecaptcha.render('review_recaptcha', {
              'sitekey' : '<?php echo $site_key?>'
            });
        }
      };      
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
Community
  • 1
  • 1
xkeshav
  • 53,360
  • 44
  • 177
  • 245
3

My Problem got resolved by doing following changes in the script code (:

i.e from internal path

<script src='static/js/recaptcha/api.js'></script>

to external google path i.e

<script src='https://www.google.com/recaptcha/api.js'></script>

Walk
  • 1,531
  • 17
  • 21
3

It works on landing page and also in bootstrap 4 popup form:

<script src="https://www.google.com/recaptcha/api.js?render=ADD-YOUR-RECAPTCHA-SITE-KEY-HERE"></script>
<script>
var interval = setInterval(function(){
  if(window.grecaptcha){
        grecaptcha.ready(function() {
            grecaptcha.execute('ADD-YOUR-RECAPTCHA-SITE-KEY-HERE', {action: 'homepage'}).then(function(token) {
              $('#i-recaptcha').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">');
            });
        });
    clearInterval(interval);
  }
}, 100);
</script>

Thanks for asking this question. :)

Kamlesh
  • 5,233
  • 39
  • 50
2

For me it was working for years then suddenly stopped.

switching the API load from

<script type="text/javascript" src="https://www.google.com/recaptcha/api.js"></script>

to having async and defer fixed it

<script type="text/javascript" src="https://www.google.com/recaptcha/api.js" async defer></script>
Mike
  • 457
  • 3
  • 13
1

Sometimes the application loads several times the script 'https://www.google.com/recaptcha/api.js after refresh, make sure your application doesn't have multiple <script async="" defer="" src="https://www.google.com/recaptcha/api.js"></script>

1

If you don't want to use a callback, another async solution is explained in the recaptcha docs:

When loading reCAPTCHA asynchronously, keep in mind that reCAPTCHA cannot be used until it has finished loading. For example, the following code would likely break:

<script async src="https://www.google.com/recaptcha/api.js"></script>
<script>
  // If reCAPTCHA is still loading, grecaptcha will be undefined.
  grecaptcha.ready(function(){
    grecaptcha.render("container", {
      sitekey: "ABC-123"
    });
  });
</script>

In some situations, adjusting script ordering can be enough to prevent race conditions. Alternatively, you can prevent race conditions by including the following code snippet on pages that load reCAPTCHA. If you are using grecaptcha.ready() to wrap API calls, add the following code snippet to ensure that reCAPTCHA can be called at any time.

<script async src="https://www.google.com/recaptcha/api.js"></script>
<script>
  // How this code snippet works:
  // This logic overwrites the default behavior of `grecaptcha.ready()` to
  // ensure that it can be safely called at any time. When `grecaptcha.ready()`
  // is called before reCAPTCHA is loaded, the callback function that is passed
  // by `grecaptcha.ready()` is enqueued for execution after reCAPTCHA is
  // loaded.
  if(typeof grecaptcha === 'undefined') {
    grecaptcha = {};
  }
  grecaptcha.ready = function(cb){
    if(typeof grecaptcha === 'undefined') {
      // window.__grecaptcha_cfg is a global variable that stores reCAPTCHA's
      // configuration. By default, any functions listed in its 'fns' property
      // are automatically executed when reCAPTCHA loads.
      const c = '___grecaptcha_cfg';
      window[c] = window[c] || {};
      (window[c]['fns'] = window[c]['fns']||[]).push(cb);
    } else {
      cb();
    }
  }

  // Usage
  grecaptcha.ready(function(){
    grecaptcha.render("container", {
      sitekey: "ABC-123"
    });
  });
</script>
Andrew
  • 18,680
  • 13
  • 103
  • 118
  • Not sure why but I couldn't get this working for v3. https://www.google.com/recaptcha/api.js?onload=loadReCaptcha&render={key} seemed to work – Ben May 12 '23 at 18:39
0

I know this is an old question but maybe this will help someone. The reason I was getting this 'Uncaught ReferenceError: grecaptcha is not defined' error was because I couldn't reach the dependency js file (recaptcha_en.js) which is hosted on www.gstatic.com. Once I solved that issue, it worked for me.

Freddie
  • 172
  • 1
  • 5
  • 15
0

I have solved the problem by updating site key and secret key. Actually I was using v3 API but used v2 configuration.

After using v3 key, my captcha is working fine.

Sarower Jahan
  • 1,445
  • 1
  • 13
  • 20