Google's reCaptcha v3 helps you detect abusive traffic on your website without user interaction. Instead of showing a challenge, it returns a score so you can choose the most appropriate action for your website.

In reCaptcha v1, every user was asked to pass a challenge by reading distorted text and typing into a box. To improve both user experience and security, Google introduced reCaptcha v2 and began to use many other signals to determine whether a request came from a human or bot. The reCaptcha v3 runs adaptive risk analysis in the background to alert you of suspicious traffic while letting your human users enjoy a frictionless experience on your site.

Since it doesn't interrupt users, you can add reCaptcha v3 to multiple pages. In this way, the adaptive risk analysis engine can identify the pattern of attackers more accurately by looking at the activities across different pages on your website. In the admin console, you can get a full overview of score distribution and a breakdown for the stats of the top 10 actions on your site, to help you identify which exact pages are being targeted by bots and how suspicious the traffic was on those pages.

Score: You get a score that tells you how suspicious an interaction is. There are three potential ways you can use the score:

  1. You can set a threshold that determines when a user is let through or when further verification needs to be done, for example, using two-factor authentication and phone verification.

  2. You can combine the score with your own signals that reCaptcha can’t access such as user profiles or transaction histories.

  3. You can use the reCaptcha score as one of the signals to train your machine learning model to fight abuse.

How to Add reCaptcha

The first step is to go to the reCAPTCHA website and login with a Google account. Then, register a new site. After registration, you will get a Site key and a Secret key.

1. Client Side Integration

Replace 'RECAPTCHA_SITE_KEY' with the key provided to you.

<script src=""></script>
grecaptcha.ready(function () {
grecaptcha.execute('RECAPTCHA_SITE_KEY', { action: 'contact' }).then(function (token) {
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;

The grecaptcha.ready function runs when the service has fully loaded and created a token for the current user. The action should relate to the current page or operation being performed.

Next, you can use a hidden form input to pass the token through the value of the input.

<input type="hidden" name="recaptcha_response" id="recaptchaResponse">

Now, the code is analysing the user, then creating a token and assigning it to a hidden input. The reCaptcha returns a score from 0.0 to 1.0 where 1.0 is very likely a good interaction, 0.0 is very likely a bot. By default, you can use a threshold of 0.5.

2. Server Side Integration

Replace 'RECAPTCHA_SECRET_KEY' with the Secret key provided to you. Server side integration involves a request to a Google URL.

$recaptcha_url = '';
$recaptcha_secret = 'RECAPTCHA_SECRET_KEY';
$recaptcha_response = $_POST['recaptcha_response'];
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);

The response is a JSON object.

$recaptcha = json_decode($recaptcha);

Next, you can take action based on the score:

if ($recaptcha->score >= 0.5) {
// Verified - send email
} else {
// Not verified - show form error

The reCaptcha Response

  • The response (for example, $recaptcha->score) is a JSON object which returns the following:
  • success: true|false, whether this request was a valid reCAPTCHA token for your site
  • score: number, the score for this request (0.0 - 1.0)
  • action: string, the action name for this request (important to verify)
  • challenge_ts: timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
  • hostname: string, the hostname of the site where the reCAPTCHA was solved
  • error-codes: [...] // optional

Error Codes

  • missing-input-secret: The secret parameter is missing.
  • invalid-input-secret: The secret parameter is invalid or malformed.
  • missing-input-response: The response parameter is missing.
  • invalid-input-response: The response parameter is invalid or malformed.
  • bad-request: The request is invalid or malformed.
  • timeout-or-duplicate: The response is no longer valid: either is too old or has been used previously.