Improve page performance lazy loading reCaptcha
Tags: javascript, beginners, webdev
Published: 2020-07-01 10:52:08

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](https://tehnoblog.org/google-invisible-recaptcha-how-to-boost-lighthouse-performance-score/) 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
<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
<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 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](https://antonioufano.com/image_uploads/1593441730947.png)

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](https://twitter.com/uf4no) 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](https://antonioufano.com/blog) where you can find other articles about web development focused on Laravel, Node.js Vue and more._ 

Happy coding!