Back to blog

Improve page performance lazy loading reCaptcha

Posted

A few days ago I ran Lighthouse in a couple of my websites and the performance score wasn't very good (around ~50). Most of the recommendations provided to improve the score were server side, like caching and compressing assets but the score gains when I applied them was not that good. I realized that what was impacting the website performance was reCaptcha.

I use reCaptcha in every page that contains a form to avoid spam so getting rid of it was not an option. After searching online for some ways to improve the situation, I found this article which explained how to solve all my issues. The solution is awesome by its simplicity: do not load recaptcha on the page load but lazy load it when the user actually interacts with one of your forms .

Let's say we have a page with a simple subscription form and we load reCaptcha as it's detailed in their docs:

<html>
<head>
  <title>My page</title>
</head>

<body>
  <header>
    <h1>My awesome website</h1>
  </header>
  <main>
    <form id="contactForm" action="#" method="POST">
      <input aria-label="Name" id="sub_name" type="text" required placeholder="Johnny Mnemonic" />
      <input aria-label="Email address" id="subEmail" type="email" required placeholder="[email protected]" />

      <input id="submitBtn" value="Subscribe" type="submit" data-sitekey="GOOGLE_RECAPTCHA_KEY"
        data-callback="sendForm">
    </form>
  </main>

  <!-- reCaptcha API JS -->
  <script src="https://www.google.com/recaptcha/api.js" defer></script>

  <script>
    function sendForm() {
      document.getElementById('contactForm').submit();
    }
  </script>

</body>

</html>

The reCaptcha API library is loaded with the page, just 1.2KB, but it automatically triggers a request to https://www.gstatic.com/recaptcha/releases/ which adds another extra 127KB to our page. And what happens if the user never interacts with the form? We've loaded a JavaScript file for no reason at all.

The solution is pretty simple and easy to implement:

<html>
<head>
  <title>My page</title>
</head>

<body>
  <header>
    <h1>My awesome website</h1>
  </header>
  <main>
    <form id="contactForm" action="#" method="POST">
      <input aria-label="Name" id="subName" type="text" required placeholder="Johnny Mnemonic" />
      <input aria-label="Email address" id="subEmail" type="email" required placeholder="[email protected]" />

      <input id="submitBtn" value="Subscribe" type="submit" data-sitekey="GOOGLE_RECAPTCHA_KEY"
        data-callback="sendForm">
    </form>
  </main>

  <script>

    function sendForm() {
      document.getElementById('contactForm').submit();
    }

    // Function that loads recaptcha on form input focus
    function reCaptchaOnFocus() {
      var head = document.getElementsByTagName('head')[0]
      var script = document.createElement('script')
      script.type = 'text/javascript';
      script.src = 'https://www.google.com/recaptcha/api.js'
      head.appendChild(script);

      // remove focus to avoid js error:
      document.getElementById('subName').removeEventListener('focus', reCaptchaOnFocus)
      document.getElementById('subEmail').removeEventListener('focus', reCaptchaOnFocus)
    };
    // add initial event listener to the form inputs
    document.getElementById('subName').addEventListener('focus', reCaptchaOnFocus, false);
    document.getElementById('subEmail').addEventListener('focus', reCaptchaOnFocus, false);
  
  </script>

</body>
</html>

Let me explain what's happenning here:

  1. We're no longer loading the reCaptcha API JS library by default
  2. We've declared a function recaptchaOnFocus that adds the script tag with the reCaptcha API JS library to our page header when it's invoked.
  3. We've added event listeners in our form inputs to invoke the recaptchaOnFocus function.

This way, our initial page load has 2 less requests and we've saved 128KB. For me this was the difference between these two results:

Lighthouse score

I hope this helps you improve your page load times but don't apply this just to reCaptcha. Think about other libraries you might be loading by default in your pages that can be lazy loaded in a similar way. I'm sure you'll be able to find some of them that are only necessary in edge cases.

Happy coding!

Included in categories

coding javascript

Did you enjoy this article? Consider sharing it on social media and following me on Twitter 🤙