Improve web performance lazy loading reCaptcha

Last updated

Antonio Ufano avatar

Antonio Ufano

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 the most 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 initial 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="eightgigs@memory.com"
        />

        <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="eightgigs@memory.com"
        />

        <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:

  • We're no longer loading the reCaptcha API JS library by default
  • 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.
  • 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 that 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!

If you enjoyed this article consider sharing it on social media or buying me a coffee ✌️

Oh! and don't forget to follow me on Twitter where I share tons of dev tips 🤙

Other articles that might help you

my projects

Apart from writing articles in this blog, I spent most of my time working on my personal projects.

lifeboard.app logo

theLIFEBOARD.app

theLIFEBOARD is a weekly planner that helps people achieve their goals, create new habits and avoid burnout. It encourages you to plan and review each week so you can easily identify ways to improve your productivity while keeping track of your progress.

Request early access
quicktalks.io logo

Quicktalks.io

Quicktalks is a place where indie hackers, makers, creators and entrepreneurs share their knowledge, ideas, lessons learned, failures and tactics they use to build successfull online products and businesses. It'll contain recorded short interviews with indie makers.

Message me to be part of it