grecaptcha: Your Guide to Google's reCAPTCHA JavaScript API

This blog walks you through integrating Google's reCAPTCHA using its JavaScript API, ensuring your website is protected with ease

in

ReCAPTCHA is a free service by Google that helps protect your website from bots and abusive traffic. It uses challenges like image recognition and checkbox selections to distinguish between humans and automated programs. Integrating reCAPTCHA is surprisingly simple, requiring just a few lines of JavaScript code.

While reCAPTCHA offers a simple way for basic implementations through its g-recaptcha tag, it also offers the grecaptcha JavaScript API, providing greater control over how and when the reCAPTCHA element is rendered. This article focuses on the grecaptcha JavaScript API, offering a detailed guide to its functionalities to understand how to get the most out of it. We will also discuss situations where the JS API is the preferred choice, and equip you to leverage its full potential.

Understanding reCAPTCHA

You’re probably already aware of Google’s reCAPTCHA offerings. For the uninitiated, reCAPTCHA comes in two flavors: reCAPTCHA v2 and reCAPTCHA v3. V2’s checkbox variant uses visible challenges like ticking a checkbox and/or identifying objects in images in a reCAPTCHA widget. It offers a clear user experience but can sometimes disrupt the flow. V2’s invisible variant removes the additional step of ticking a dedicated checkbox for verification and instead relies on the user’s interactions with the form (such as clicking the submit button) to judge if they are a human or a bot.

ReCAPTCHA v3 takes a more subtle approach. It analyzes user behavior behind the scenes, assigning a risk score based on various factors. This allows for a smoother user experience but requires more configuration on your end. Also, Google suggests including the reCAPTCHA v3 script on as many pages of your website as possible for best results.

Integrating reCAPTCHA with the JavaScript API

To get started with reCAPTCHA and the JavaScript API, you’ll need to obtain your reCAPTCHA key from the Google Cloud Console. Head over to the reCAPTCHA admin console and create a new site. Then, you will be able to access your reCAPTCHA site key and secret key. Make sure to keep the secret key confidential as it’s used for server-side verification.

Including the reCAPTCHA Library

Next, you’ll need to include the reCAPTCHA JavaScript library in your web pages. Here’s how you can do it for v2:

  <script src="https://www.google.com/recaptcha/api.js?onload=myCallBackFunction&render=explicit" async defer></script>

This code snippet loads the library from Google’s servers. The onload parameter specifies a callback function (in this case, myCallBackFunction()) that will be executed once the library is loaded. This lets your script know that the Google reCAPTCHA library has been loaded completely and you can now render the reCAPTCHA widget and execute the reCAPTCHA verification as you’d like.

The render parameter has been set to explicit to set the script to render the reCAPTCHA widget on command, and not automatically on the first g-recaptcha tag that it finds on the page (which is the default behavior).

The async and defer attributes are crucial for optimal loading. async allows the script to load without blocking the rendering of the page, while defer ensures the script executes after the HTML parsing is complete. Setting these attributes eliminates the possibility of race conditions between the script being loaded and the onload callback being defined on the page.

For v3, the script tag needs to look like this:

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

You only need to provide the reCAPTCHA site key to the script in the render parameter of the script URL. Instead of using an onload callback, you can make use of the grecaptcha.ready callback in your code to know when reCAPTCHA is loaded and ready.

Rendering the reCAPTCHA Widget

Once the library is loaded, there are two things you need to do regardless of which variant of reCAPTCHA you are using: render the reCAPTCHA (even in the case of invisible variants) and execute the reCAPTCHA challenge.

In the reCAPTCHA v2 Checkbox variant, the user needs to manually complete the challenge, so you only need to programmatically render the reCAPTCHA widget after the grecaptcha library has been loaded (through the onload parameter you saw earlier). Once the user completes the on-screen reCAPTCHA challenge, the form will receive the token of the user’s response, and when the user submits the form, the token will be sent as part of the form data.

The grecaptcha.render method takes an object with various configuration options:

  grecaptcha.render(containerElement, {
    sitekey: 'your_site_key',
    theme: 'light', // or 'dark'
    size: 'normal', // or 'compact'
    tabindex: 3,
    callback: verifyResponse, // optional callback function
    'expired-callback': handleExpiredToken, // optional callback function
    'error-callback': handleRenderError // optional callback function
  });

Here’s a quick explanation of what each of the parameters are for:

  • containerElement: This is either the ID of a DOM element where the widget should be rendered or the element itself.
  • sitekey: This is your public site key obtained from the Google Cloud Console.
  • theme: You can choose between a light or dark theme for the widget.
  • size: You can specify the size of the widget as normal or compact.
  • tabindex: You can set this attribute for accessibility purposes if any other elements in your page also use this functionality.
  • Callback functions: These are optional functions that handle specific events:
    • callback: This function is triggered when the user successfully completes the challenge. It receives a token that needs to be sent to your server for verification.
    • expired-callback: This function is called if the user’s challenge-response expires before verification.
    • error-callback: This function handles any errors encountered during the rendering process.

Similar to the checkbox variant, you need to programmatically render the reCAPTCHA widget first for the reCAPTCHA v2 Invisible variant as well. However, since this variant is supposed to work invisibly, the user will not complete any manual challenges to generate the token, so you need to call the execute method programmatically to generate the token.

The execute method executes the reCAPTCHA challenge in the background and upon a successful execution, populates the form with the response token. If the background execution fails, it will trigger a manual challenge for the user to complete. Once done, the form will receive the response token.

You can choose when to call this method. For a seamless experience, developers often call this method right after the render method completes, which means that the form receives the reCAPTCHA token while the user is busy filling it, and when the user submits the form, it is instant. However, if the user takes too long to fill the form, the token can expire in this time and the submission might be rejected from your backend. This is why it is better to call this method on the onsubmit event of your form to stop the form from being submitted, generate the reCAPTCHA token, and then submit the form. This can add a very slight delay between when the user clicks the submit button and when the form is actually submitted, but there are ways to gracefully handle that on the frontend.

The grecaptcha.execute() method takes the following configuration options:

  • widget_id: The ID of the widget created by the grecaptcha.render call. This is optional, so if you do not provide this value, it will default to the ID of the first widget that is created (i.e. rendered) on the page.
  • sitekey: This is your public site key obtained from the Google Cloud Console.
  • action: This is an object with a single key-value pair, where the value for the key action defines the name of the action, or the operation, for which the verification was triggered. You could use this for operations like login, form submission, etc.This is only used with score-based reCAPTCHA variants, such as the reCAPTCHA v3. An example value for this parameter is { "action": "login" }.

For reCAPTCHA v3, you don’t need to call the render method. That is because, if you remember, the suggested way to load the grecaptcha API for reCAPTCHA v3 is:

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

The library, once loaded, will automatically render the reCAPTCHA widget for you. You just need to call execute when you want to generate the reCAPTCHA token, preferrably just before submitting the form (or doing any kind of action that you would like to protect with reCAPTCHA). Since the library renders right after loading all by itself, it can sometimes take longer than usual to be ready, so it is imporant to check whether the library is ready or not before calling exceute. Therefore, here’s how you can call the Google reCAPTCHA v3 challenge programmatically on the form submit event:

  <script>
    function submitForm(ev) {
      ev.preventDefault();
      grecaptcha.ready(function() {
        grecaptcha.execute('reCAPTCHA_site_key', {action: 'submit'}).then(function(token) {
            // Submit the form to your backend server here
        });
      });
    }
  </script>

Handling User Response

The callback function receives a token as its argument. This token represents the user’s response to the challenge and needs to be sent to your server for verification along with your secret key. On the server side, you can use Google’s reCAPTCHA verification API to validate the token and determine if the user is legitimate.

Here’s an example of a basic callback function:

  // Add the following function to your server-side code
  function verifyResponse(token) {
    fetch('https://www.google.com/recaptcha/api/siteverify', {
      method: 'POST',
      body: JSON.stringify({
          secret: "your-secret-key",
          response: "the token received from the callback function",
          remoteip: "the user's IP address" // optional
      })
    })
    .then(response => response.json())
    .then(data => {
      /**
      The data object looks like the following:
          {
            "success": true|false,
            "challenge_ts": timestamp,  // timestamp when the challenge was loaded (ISO format)
            "hostname": string,         // the hostname of the site where the reCAPTCHA verification was done
            "error-codes": [...]        // optional
          }
      **/
      if (data.success) {
        // User is legitimate, proceed with form submission or other actions.
      } else {
        // Handle invalid token case, display error message to user.
      }
    });
  }

This example sends the token to the server-side endpoint /siteverify on the reCAPTCHA API using a POST request. The response from the server indicates whether the token is valid, allowing you to proceed with the user’s action (like form submission) or display an error message if the verification fails.

Handling reCAPTCHA with Formspree

Instead of sending the reCAPTCHA token to your backend for verification, you could just use Formspree when you are using grecaptcha with forms.

If you have a straightforward form, Formspree supports setting up reCAPTCHA v3 verification with just a few steps. However, if you would like to gain more control over how and when the reCAPTCHA verification is triggered using grecaptcha, you can set up your reCAPTCHA keys in the Formspree dashboard and send the reCAPTCHA token to Formspree by adding it to a property named g-recaptcha-response in your form data to verify it.

Here’s an example of triggering the reCAPTCHA verification using grecaptcha and sending the reCAPTCHA token to Formspree using this field:

  <html>
      <head>
          <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
          <script src="https://www.google.com/recaptcha/api.js?render={your-site-key}"></script>
      </head>
      <body>
          <button onclick="captcha()" class="btn btn-primary">click me</button>
          <script>
            function captcha() {
                  grecaptcha.ready(function () {
                      grecaptcha.execute("{your-site-key}", { action: "submit" }).then(function (token) {
                          $.ajax({
                              url: "https://formspree.io/f/{your-form-id}",
                              method: "POST",
                              dataType: "json",
                              data: { email: "test@email.com", message: "Hello world!", "g-recaptcha-response": token },
                              success: () => {
                                  alert("Done!");
                              },
                              error: (err) => {
                                  alert("Something wrong!", err);
                              },
                          });
                      });
                  });
              }
          </script>
          <html></html>
      </body>
  </html>

Best Practices for Using reCAPTCHA

You should always provide clear and informative messages to users if the reCAPTCHA challenge fails to load or the verification process encounters any problems. A generic “something went wrong” can be frustrating for users, and a frustrated user is very likely to abandon your website.

Also, implement mechanisms to gracefully address situations like network issues or incorrect API keys. Apart from providing a detailed error message to the user, make a note of such incidents internally and resolve them as quickly as possible.

Since the reCAPTCHA library is an external script, consider strategies to minimize its impact on initial page load time. One approach is lazy loading, where the library is loaded only when the reCAPTCHA widget is needed. This can significantly improve perceived website performance, especially for users on slower connections.

The security of your reCAPTCHA implementation depends on keeping your secret key confidential. Never expose it on the client side or embed it directly in your code. Treat it with the same care as any other sensitive credential and store it securely on your server.

When to Choose g-recaptcha Tag vs JS API

While the grecaptcha JavaScript API offers a powerful and flexible solution for reCAPTCHA integration, there are situations where the simpler g-recaptcha HTML tag might be a better fit. Here’s a breakdown to help you decide:

g-recaptcha Tag: The Quick and Easy Option

The g-recaptcha tag is ideal for straightforward implementations where you only need basic functionality. It’s a simple HTML element that you can embed directly into your form. Here’s an example:

  <div class="g-recaptcha" data-sitekey="your_site_key"></div>

This code snippet creates a reCAPTCHA widget with your site key. However, the tag offers limited control. You can’t customize the rendering behavior, trigger the challenge conditionally, or handle user interactions with the widget. Additionally, error handling and verification token retrieval require server-side scripting.

JS API: Power and Flexibility for Complex Scenarios

The grecaptcha JavaScript API is a better option when you need more control over reCAPTCHA integration. Here’s why:

  • Flexibility and customization: The JS API allows you to trigger the challenge display based on specific user actions or events. This means you can control when the user encounters the challenge, ensuring a smoother experience for low-risk interactions.
  • Advanced callbacks: You can leverage callback functions to handle successful responses, expired tokens, or errors. This enables you to tailor the user experience based on the reCAPTCHA outcome. For instance, you can display a success message upon verification or provide a retry option for expired tokens. This is not possible with the HTML tag.
  • Integration with other validations: The JS API can easily integrate with other form validation processes on your website. You can combine reCAPTCHA verification with custom validation rules for a robust security layer.

Trade-offs to Consider

While the JS API offers greater power, it comes with a slightly steeper learning curve. Implementing the JS API requires more coding compared to the tag. You’ll need to include the JavaScript library, use the grecaptcha.render() method, and handle user interactions through callback functions.

If you need a simple solution for basic reCAPTCHA integration, the g-recaptcha tag is a great starting point. However, for scenarios where you require more control, customization, and integration with other functionalities, the grecaptcha JavaScript API is the way to go. Remember, a well-implemented reCAPTCHA shouldn’t significantly hinder user experience. Choose the approach that strikes the right balance between security and a smooth user journey.

Platform-Specific Libraries

For developers working with popular web development frameworks, integrating reCAPTCHA becomes even smoother with the availability of platform-specific libraries. These libraries provide pre-built components that simplify the integration process and offer a familiar syntax within your chosen framework.

Here are some examples:

  • React: The react-google-recaptcha library provides a React component that wraps the reCAPTCHA functionality. This allows you to easily integrate the widget into your React components and leverage React’s state management for handling user interactions and verification tokens.
  • Angular: The ngx-recaptcha library offers a similar solution for Angular applications. It provides directives that can be applied to form elements, making it straightforward to add reCAPTCHA challenges to your Angular forms.
  • Vue.js: The vue-recaptcha library simplifies reCAPTCHA integration for Vue.js projects. It provides a Vue component that can be used within your templates and interacts seamlessly with Vue’s data binding and event-handling mechanisms.

These libraries not only simplify the integration process but also ensure consistency with your framework’s coding style and best practices. Additionally, they often stay up-to-date with the latest changes in the reCAPTCHA API, saving you time and effort on maintaining your implementation.

To get started with these libraries, refer to their respective documentation available on their home pages. The documentation typically provides installation instructions, usage examples, and configuration options specific to your chosen framework. By leveraging these platform-specific solutions, you can significantly reduce development time and create a seamless reCAPTCHA experience within your framework-based web application.

Conclusion

ReCAPTCHA’s JavaScript API empowers you to add a powerful layer of security to your website with surprising ease. It offers a flexible solution that can be tailored to your specific needs, balancing robust protection against bots with a smooth user experience.

While alternative solutions exist, reCAPTCHA’s integration with Google’s advanced risk analysis engine makes it a compelling choice. For developers working with popular frameworks, platform-specific libraries further simplify the integration process. So, if you’re looking to shield your website from malicious traffic, consider implementing reCAPTCHA’s JavaScript API – a simple yet powerful tool to keep your web forms secure.


Got Feedback?