DEV Community

Antonio
Antonio

Posted on • Updated on • Originally published at antonioufano.com

Improve page performance lazy loading reCaptcha

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 were not that good. I realized that one the things 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 the website 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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Let me explain what's happening 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.

If you liked this article, you can follow me on Twitter where I share dev tips like this one, updates about my projects and insteresting articles I find online 😎


This article was originally posted in my blog where you can find other articles about web development focused on Laravel, Node.js Vue and more.

Happy coding!

Discussion (1)

Collapse
abdulhade profile image
abdulhade

Excellent idea! But this function will add the script every focus event, right? Do you think that's a good idea if you check if this script was already added?