reCAPTCHA is a free service that protects your website from spam and abuse. reCAPTCHA uses an advanced risk analysis engine and adaptive CAPTCHAs to keep automated software from engaging in abusive activities on your site. It does this while letting your valid users pass through with ease.

reCAPTCHA offers more than just spam protection. Every time our CAPTCHAs are solved, that human effort helps digitize text, annotate images, and build machine learning datasets. This in turn helps preserve books, improve maps, and solve hard AI problems.

This codelab will walk you through building a form supporting reCAPTCHA with both reCAPTCHA V2 and the Invisible reCAPTCHA.

What you'll learn

What you'll need

Install and verify web server

This codelab can either be run locally or through the gcloud shell in Google Cloud Platform. To get started with the gcloud shell go to https://console.cloud.google.com/appengine/start.

Download the Code

Clone all the code for this codelab:

git clone https://github.com/googlecodelabs/recaptcha-codelab.git

Or Download Zip

For Java:

cd recaptcha-codelab/phase1
mvn appengine:devserver

For Python:

cd recaptcha-codelab/phase1-python
python server.py

In the web browser, go to http://localhost:8080 to see the example UI without reCAPTCHA integrated.

For the purpose of this codelab you can skip this step. The site key provided in this codelab will work only on localhost. We recommend if you have time that you follow through and create your own registration in the admin console. Before you use reCAPTCHA in development or production you will need to do this step.

First go to The reCAPTCHA Admin Site.

Choose ‘Invisible reCAPTCHA' as the type of captcha.

Fill in the list of domains you wish to show your captcha. For the codelab use ‘localhost' or your machine name. The reCAPTCHA site key you create will only work on these domains. Save the site key and secret key for the later stages.

To add reCAPTCHA validation to your website edit phase1/src/main/web/feedback.jsp.

First add a script tag to the html <head> element.

feedback.jsp

<html>
 <head>
   <title>Suggestion page</title>
   <script src='https://www.google.com/recaptcha/api.js'></script>

Change the attributes to the submit button. Add class='g-recaptcha' data-sitekey="YOUR SITE KEY" and add a data-callback. The reCAPTCHA library will call the data-callback after completing the challenge.

feedback.jsp

      <button class="g-recaptcha"
       data-sitekey="6LfeHx4UAAAAAAKUx5rO5nfKMtc9-syDTdFLftnm"
       data-callback="onSubmit">Submit</button>

The full file should be:

feedback.jsp

<!DOCTYPE html>
<html>
  <head>
    <title>Suggestion page</title>
    <script src='https://www.google.com/recaptcha/api.js'></script>
    <script>
      function onSubmit() {
        document.getElementById('demo-form').submit();
      }
    </script>
    <style>
      body {
        font-family: Helvetica, sans-serif;
      }
      .status-message {
        background-color: #5ff;
        margin-bottom: 10px;
        text-align: center;
      }
      textarea {
        margin: 10px 0;
        resize: none;
      }
    </style>
  </head>
  <body>
    <h3>Give us feedback on our new webpage!</h3>
     <% if (Boolean.TRUE.equals(request.getAttribute("success"))) { %>
         <div class='status-message'>Thanks for the feedback!</div>
       <% } else if (Boolean.FALSE.equals(request.getAttribute("success"))) { %>
         <div class='status-message'>There was an error.</div>
       <% }%>
    <form id='demo-form' action='/feedback' method='POST'>
      Your comment <br><textarea name='feedback' cols='50' rows='5'></textarea><br>
      <!-- Replace this with your site key -->
     <button class="g-recaptcha"
       data-sitekey="6LfeHx4UAAAAAAKUx5rO5nfKMtc9-syDTdFLftnm"
       data-callback="onSubmit">Submit</button>
    </form>
  </body>
</html>

That's it for the client side. This will enable reCAPTCHA on your html but will not validate that the user successfully passed. A full description of widget options can be found on our developer site.

The completed version can be found in final/src/main/web/feedback.jsp.

Next you will need to verify the reCAPTCHA token on your server.

In "Registering with the reCAPTCHA Admin Console" we created a new site key. As part of that process a site secret was created. The site secret is necessary to validate the reCAPTCHA solution. For the purposes of this code lab you can use the default keys provided. These will only work on localhost.

The validation of the reCAPTCHA token is done by sending a POST request to https://www.google.com/recaptcha/api/siteverify. The details are in Verifying the user's response.

To validate the reCAPTCHA token, edit the FeedbackServlet found in phase1/src/main/java/com/example/feedback/FeedbackServlet.java.

First add a number of constants to the top of the FeedbackServlet class. These specify the parameters to be sent to the reCAPTCHA server. If you registered your site with the reCAPTCHA Admin Console, you will need to replace the SITE_SECRET below.

FeedbackServlet.java

 public class FeedbackServlet extends HttpServlet {
    // Replace this with your site secret.
    private static final String SITE_SECRET = "6LfeHx4UAAAAAFWXGh_xcL0B8vVcXnhn9q_SnQ1b";
    private static final String SECRET_PARAM = "secret";
    private static final String RESPONSE_PARAM = "response";
    private static final String G_RECAPTCHA_RESPONSE = "g-recaptcha-response";
    private static final String SITE_VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify";

Next add a method to call the reCAPTCHA site verify api. A post and parse json method has already been provided.

FeedbackServlet.java

private JSONObject performRecaptchaSiteVerify(String recaptchaResponseToken)
       throws IOException {
 URL url = new URL(SITE_VERIFY_URL);
 StringBuilder postData = new StringBuilder();
 addParam(postData, SECRET_PARAM, SITE_SECRET);
 addParam(postData, RESPONSE_PARAM, recaptchaResponseToken);

 return postAndParseJSON(url, postData.toString());
}

Next, use the performRecaptchaSiteVerify method in your post method:

FeedbackServlet.java

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
       throws IOException, ServletException {
 JSONObject jsonObject = performRecaptchaSiteVerify(req.getParameter(G_RECAPTCHA_RESPONSE));
 boolean success = jsonObject.getBoolean("success");
 req.setAttribute("success", success);
 System.out.println("Success = " + success);
 req.getRequestDispatcher("/feedback.jsp").forward(req, resp);
}

You're all done! Now reload the server and give it a try. The completed version can be found in final/src/main/java/com/example/feedback/FeedbackServlet.java

You now have a basic integration with reCAPTCHA to protect your form. In the background, we are verifying the user and will sometimes show a reCAPTCHA challenge to make sure that your website is protected from abuse. More details and options can be found on our developer site.

Let's update the frontend to call Invisible reCAPTCHA with your favorite text editor.

First let's add a script tag to the html <head> element in feedback.html.

feedback.html

<html>
 <head>
   <title>Suggestion page</title>
   <script src='https://www.google.com/recaptcha/api.js'></script>

Now update the attributes to the submit button. Add class='g-recaptcha' data-sitekey="YOUR SITE KEY" and add a data-callback.

feedback.html

     <button class="g-recaptcha"
       data-sitekey="6LfeHx4UAAAAAAKUx5rO5nfKMtc9-syDTdFLftnm"
       data-callback="onSubmit">Submit</button>

The full file should be:

feedback.html

<!DOCTYPE html>
<html>
<head>
  <title>Suggestion page</title>
  <script src='https://www.google.com/recaptcha/api.js'></script>
  <script>
    function onSubmit() {
      document.getElementById("demo-form").submit();
    }
  </script>
  <style>
    body {
      font-family: Helvetica, sans-serif;
    }
    .status-message {
      background-color: #5ff;
      margin-bottom: 10px;
      text-align: center;
    }
    textarea {
      margin: 10px 0;
      resize: none;
    }
  </style>
</head>
<body>
  <h3>Give us feedback on our webpage!</h3>
  <div class="status-message">%s</div>
  <form id="demo-form" action="/feedback" method="POST">
    Your comment <br><textarea name="feedback" cols="50" rows="5"></textarea><br>
    <!-- Replace this with your site key -->
    <button class="g-recaptcha"
            data-sitekey="6LfeHx4UAAAAAAKUx5rO5nfKMtc9-syDTdFLftnm"
            data-callback="onSubmit">Submit</button>
  </form>
</body>
</html>

That's it for the client side. This will enable reCAPTCHA on your html but will not validate that the user successfully passed. A full description of widget options can be found on our developer site.

The completed version can be found in final-python/feedback.html.

Next you will need to verify the reCAPTCHA token on your server.

In "Registering with the reCAPTCHA Admin Console" we created a new site key. As part of that process a site secret was created. The site secret is necessary to validate the CAPTCHA solution. For the purposes of this code lab you can use the default keys provided. These will only work on localhost.

The validation of the reCAPTCHA token is done by sending a POST request to https://www.google.com/recaptcha/api/siteverify. The details are in Verifying the user's response.

To validate the reCAPTCHA token, let's update the server. First we need to add the site secret and site verify constants.

server.py

SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'
SITE_SECRET = '6LfeHx4UAAAAAFWXGh_xcL0B8vVcXnhn9q_SnQ1b'
RECAPTCHA_RESPONSE_PARAM = 'g-recaptcha-response'

Then we need to update our POST handler to verify the token.

server.py

def do_POST(self):
    self.set_headers();
    post_body = parse_qs(self.rfile.read(int(self.headers['Content-Length'])))

    success = False
    if RECAPTCHA_RESPONSE_PARAM in post_body:
      token = post_body[RECAPTCHA_RESPONSE_PARAM][0]
      resp = urllib.urlopen(
          SITE_VERIFY_URL, urllib.urlencode(
              {'secret': SITE_SECRET, 'response': token}, True)).read()
      if json.loads(resp).get("success"):
        success = True

    if success:
      message = 'Thanks for the feedback!'
    else:
      message = 'There was an error.'
    self.wfile.write(open(curdir + sep + 'feedback.html').read() % message)

The final file should look like this:

server.py

import json
import urllib
from os import curdir, sep
from urlparse import parse_qs
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'
SITE_SECRET = '6LfeHx4UAAAAAFWXGh_xcL0B8vVcXnhn9q_SnQ1b'
RECAPTCHA_RESPONSE_PARAM = 'g-recaptcha-response'

class Handler(BaseHTTPRequestHandler):
  def set_headers(self):
    self.send_response(200)
    self.send_header('Content-type', 'text/html')
    self.end_headers()

  def do_GET(self):
    self.set_headers();
    self.wfile.write(open(curdir + sep + 'feedback.html').read() % '')

  def do_POST(self):
    self.set_headers();
    post_body = parse_qs(self.rfile.read(int(self.headers['Content-Length'])))

    success = False
    if RECAPTCHA_RESPONSE_PARAM in post_body:
      token = post_body[RECAPTCHA_RESPONSE_PARAM][0]
      resp = urllib.urlopen(
          SITE_VERIFY_URL, urllib.urlencode(
              {'secret': SITE_SECRET, 'response': token}, True)).read()
      if json.loads(resp).get("success"):
        success = True

    if success:
      message = 'Thanks for the feedback!'
    else:
      message = 'There was an error.'
    self.wfile.write(open(curdir + sep + 'feedback.html').read() % message)

if __name__ == '__main__':
  httpd = HTTPServer(('', 8080), Handler)
  httpd.serve_forever()

You're all done! Now reload the server and give it a try. The completed version can be found in final-python/server.py. You now have a basic integration with reCAPTCHA to protect your form. In the background, we are verifying the user and will sometimes show a reCAPTCHA challenge to make sure that your website is protected from abuse. More details and options can be found on our developer site.