Loading reCAPTCHA

This document discusses best practices for loading the reCAPTCHA script tag. This information is applicable to both reCAPTCHA v2 and v3.

Loading reCAPTCHA asynchronously

All versions of the reCAPTCHA can be loaded asynchronously. Loading reCAPTCHA asynchronously does not impact its ability to identify suspicious traffic. Due to the performance benefits of asynchronous scripts, loading reCAPTCHA asynchronously is generally recommended.

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

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>

As an alternative, sites that use the v2 API may find it useful to use the onload callback; the onload callback is executed when reCAPTCHA finishes loading. The onload callback should be defined before loading the reCAPTCHA script.

<script>
  const onloadCallback = function() {
    console.log("reCAPTCHA has loaded!");
    grecaptcha.reset();
  };
</script>
<script async src="https://www.google.com/recaptcha/api.js?onload=onloadCallback”></script>

If loading reCAPTCHA asynchronously is not an option, including preconnect resource hints for reCAPTCHA is strongly recommended. This will minimize the amount of time that the script download blocks the parser.

Using resource hints

Including the following resource hints in the <head> of the document will reduce the amount of time that it takes to deliver the resources used by reCAPTCHA. The preconnect resource hint instructs the browser to establish an early connection with a third-party origin.

<link rel="preconnect" href="https://www.google.com">
<link rel="preconnect" href="https://www.gstatic.com" crossorigin>

Lazy Loading

Generally speaking, the more context that reCAPTCHA has about a page, the better informed it is to determine whether user actions are legitimate. This is particularly true when using versions of reCAPTCHA that don’t rely on user challenges. Thus, waiting to load reCAPTCHA until a specific restricted action occurs (for example, form submission) is generally not recommended.