Adding Google reCAPTCHA v3 to your Django Forms

May 15, 2020, 12:06 p.m.
Django · 9 min read
Adding Google reCAPTCHA v3 to your Django Forms
Last Modified: March 15, 2021, 5:42 p.m.

What is Google reCAPTCHA?

reCAPTCHA is a free Google service designed to protect your website from unwanted bots submitting forms.

While previous versions required some level of user interaction with "I'm not a robot" checkboxes, Google reCAPTCHA v3 tracks the interactions with your site and detects high-risk behavior.

reCAPTCHA can be added to any HTML form, but this tutorial will cover how to complete the Django Google reCAPTCHA v3 integration.

 

Django Google reCAPTCHA v3 steps:

  1. Add domain to reCATCHA Admin Console
  2. Add reCAPTCHA keys to your Django project settings
  3. Add reCAPTCHA scripts to the HTML template
  4. Add reCAPTCHA hidden input to the HTML template
  5. Test reCAPTCHA v3
  6. Hide reCAPTCHA v3 badge

 


 

Add a domain to Google reCAPTCHA Admin Console

Before Google reCAPTCHA can track user interaction on your site, you need to register a new domain.

Visit google.com/recaptcha and click on "Admin console".  Sign in with a Google account then fill out the domain registration form.

Label your reCAPTCHA something related to the Django site, click "reCAPTCHA v3", then add your website domain(s).

Add your localhost domain (i.e. 127.0.0.1) if you are still in the development process. 

When you are done with the form click "Submit".

Update and add new domains to the form as needed.

Register domain

 

View your reCAPTCHA keys

Google reCAPTCHA will then generate a set of keys used to connect to your project. The first is the site key and the second is the secret key. Think of these as a username and password.

The keys can be accessed at any time in the Google reCAPTCHA Admin console under "Settings".

reCAPTCHA keys

 

Django Google reCAPTCHA v3 Integration

Add Google reCAPTCHA secret key to Django settings

env > mysite > mysite > settings.py

...

# SECURITY WARNING: keep the secret key used in production secret!
...
GOOGLE_RECAPTCHA_SITE_KEY = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' #your reCAPTCHA SITE key 

GOOGLE_RECAPTCHA_SECRET_KEY = 'SSSSSSSSSSSSSSSSSSSSSSSSSSS' #your reCAPTCHA SECRET key 

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

...

Start by adding your Google reCAPTCHA site key and secret key, found in the Google reCAPTCHA admin console, to your settings.py file.

Make sure to place quotation marks around each key.

We also highly recommend using Python Decouple to properly secure this secret configuration key.

 

Pass the reCAPTCHA site key as context 

env > mysite > main > views.py

from django.shortcuts import render, redirect
from .forms import ContactForm
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse
from django.config import settings #import settings from Django config


# Create your views here.
def contact(request):
	...
      
	form = ContactForm()
	return render(request, "main/contact.html", {'form':form, 'recaptcha_site_key':settings.GOOGLE_RECAPTCHA_SITE_KEY})

Go to view.py and add recaptcha_site_key as context to the contact view.

Get the entire contact view from Build a Django Contact Form

 

Add Django messages framework to your project

Django messages framework

If you haven't already, add the Django messages framework to your project. 

The Django messages framework allows flash messages or notifications to display after user interaction.

We will use these in the templates and views, letting the user know if they passed the reCAPTCHA.

Follow this guide if you have never used Django messages. 

 

How to add the reCAPTCHA v3 script in HTML template

env > mysite > main > templates > main > contact.html

<!doctype html>
<html lang="en">
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- reCAPTCHA API -->
  <script src='https://www.google.com/recaptcha/api.js?render={{recaptcha_site_key}}'></script>

  <title>Django - Google reCAPTCHA v3</title>
</head>
<body>

  {% include 'main/includes/messages.html' %}



  <!--Contact form-->
  ...

</body>
</html>

Add the Google reCAPTCHA API script to your project's HTML file and set render equal to {{recaptcha_site_key}}.

 

Add the grecaptcha.execute method

env > mysite > main > templates > main > contact.html

<!doctype html>
<html lang="en">
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- reCAPTCHA API -->
  <script src='https://www.google.com/recaptcha/api.js?render={{recaptcha_site_key}}'></script>


  <title>Django - Google reCAPTCHA v3</title>
</head>
<body>

  {% include 'main/includes/messages.html' %}



  <script>
    //global grecaptcha
    grecaptcha.ready(function() {
      grecaptcha.execute('{{recaptcha_site_key}}', {action: "/contact/"}).then(function(token) {
        document.getElementById('g-recaptcha-response').value = token;
      });
    });
  </script>



  <!--Contact form-->
  ...

</body>
</html>

Call grecaptcha.execute on the action you want to track, in this case contact.

Also, get the token we need for the view.py.

 

Add the Google reCAPTCHA g-recaptcha-response to the Django form

env > mysite > main > templates > main > contact.html

<!doctype html>
<html lang="en">
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- reCAPTCHA API -->
  <script src='https://www.google.com/recaptcha/api.js?render={{recaptcha_site_key}}'></script>


  <title>Django - Google reCAPTCHA v3</title>
</head>
<body>

  {% include 'main/includes/messages.html' %}



  <script>
    //global grecaptcha
    grecaptcha.ready(function() {
      grecaptcha.execute('{{recaptcha_site_key}}', {action: "/contact/"}).then(function(token) {
        document.getElementById('g-recaptcha-response').value = token;
      });
    });
  </script>



  <!--Contact form-->
  <div style="margin:80px">
    <h1>Contact</h1>

    <h4>Contact us directly if you have any questions</h4>
    <p>
     Please write your name, email address and a message below if you have any questions.
     One of our staff members will be happy to contact you directly and answer your questions as soon as possible. 
   </p>
   <form method="post" id="contactform">
    {% csrf_token %}
    {{form.as_p}}
    <!-- reCAPTCHA input -->
    <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response"> 
    <button type="submit">Submit</button>
  </form>
</div>

</body>
</html>

Within the form element add a hidden input element with the id and name attribute values g-recaptcha-response.

Save the changes to the file. 

 

View the reCPATCHA badge in the browser

Google v3 reCAPTCHA badge

You should now see the reCAPTCHA badge on the lower right side of the page. 

 

Install the Requests package

Windows Command Prompt

C:\Users\Owner\desktop\code> pip install requests

Now let's install the Requests package so we don't need to encode our reCAPTCHA data in the views.py.

This package makes posting to the reCPATCHA API extremely simple.

 

Add the g-recaptcha-response request to the Django views file

env > mysite > main > views.py

from django.shortcuts import render, redirect
from .forms import ContactForm
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse
from django.conf import settings
from django.contrib import messages
import requests                       #import requests

# Create your views here.
def homepage(request):
	return render(request=request, template_name='main/home.html')

def contact(request):
	if request.method == 'POST':
		form = ContactForm(request.POST)
		if form.is_valid():

			''' reCAPTCHA validation '''
			recaptcha_response = request.POST.get('g-recaptcha-response')
			data = {
			'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
			'response': recaptcha_response
			}
			r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
			result = r.json()

			print(result)

			''' if reCAPTCHA returns True '''
			if result['success']:
				''' Send email '''
				subject = "Website Inquiry" 
				body = {
				'first_name': form.cleaned_data['first_name'], 
				'last_name': form.cleaned_data['last_name'], 
				'email': form.cleaned_data['email_address'], 
				}
				message = "\n".join(body.values())

				try:
					send_mail(subject, message, 'admin@example.com', ['admin@example.com']) 
				except BadHeaderError:
					return HttpResponse('Invalid header found.')
				messages.success(request, "Message sent." )
				return redirect ("main:homepage")

			''' if reCAPTCHA returns False '''
			messages.error(request, 'Invalid reCAPTCHA. Please try again.')

	form = ContactForm()
	return render(request, "main/contact.html", {'form':form, "recaptcha_site_key":settings.GOOGLE_RECAPTCHA_SITE_KEY})

Go to views.py and import requests.

Add the reCAPTCHA validation to the form validation.

Set recaptcha_response equal to the g-recaptcha-response token value in the contact.html.

Create a dictionary called data containing the GOOGLE_RECPATCHA_SECRET_KEY from the settings.py and the recaptcha_response declared above. 

Create a Response object called r

Now make a POST request to the Google's reCAPTCHA API.

Then use the JSON decoder to print the results so we can make sure the POST request worked. Comment out the print when you're done testing.

If the reCAPTCHA returns true, the contact form information will send as normal. If the reCAPTCHA is false, then a Django message will state "Invalid reCAPTCHA. Please try again."

 

Testing the Google reCAPTCHA

reCAPTCHA JSON object response

Command Prompt

{'success': True, 'challenge_ts': '2021-03-15', 'hostname': '127.0.0.1', 'score': 0.9, 'action': '/contact/'}
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Website Inquiry
From: admin@example.com
To: admin@example.com
Date: Mon, 15 Mar 2021 23:59:27 -0000
Message-ID: <0000000000000000000000000000000000>

John
Smith
test@gmail.com
Hello, this is a test.
-------------------------------------------------------------------------------

Fill out the form and click submit. You should be redirected to the homepage and see the notification "Message sent". 

If you look at the command prompt you'll see the printed reCAPTCHA JSON object response along with the email message. 

 

 

Solving error codes

reCAPTCHA error codes

Command Prompt

{'success': False, 'error-codes': ['invalid-input-response']}

If you get an error and the command prompt states 'success': False, pay attention to the error code.

Each error code comes with a corresponding description.

 

OPTIONAL: Hide protected by reCAPTCHA badge

...

<!--Change the opacity to zero to hide the badge-->
<style>
    .grecaptcha-badge {
         opacity:0; !important;
    }
</style>

<script>
//global grecaptcha
  ...
</script>


<!--Contact form-->
	<div style="margin:80px">
		<h1>Contact</h1>
		<h4>Contact us directly if you have any questions</h4>
		<p>
			Please write your name, email address and a message below if you have any questions.
			One of our staff members will be happy to contact you directly and answer your questions as soon as possible. 
		</p>
		<form method="post">
        {% csrf_token %}
            {{form.as_p}}
            <!--add the reCAPTCHA Privacy and Terms of Service disclosure-->
            <p>This site is protected by reCAPTCHA and the Google
                <a href="https://policies.google.com/privacy">Privacy Policy</a> and
                <a href="https://policies.google.com/terms">Terms of Service</a> apply.
            </p>
            <!-- reCAPTCHA input -->
            <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response"> 
            <button type="submit">Submit</button>
        </form>
    </div>

...

If you wish to hide the protected by Google reCAPTCHA badge, you can do so with the <style> element above but you are required to disclose reCAPTCHA with a statement next to the form submission.

 

Add Google reCAPTCHA Terms and Conditions link

<!--Contact form-->
	<div style="margin:80px">
		<h1>Contact</h1>
		<h4>Contact us directly if you have any questions</h4>
		<p>
			Please write your name, email address and a message below if you have any questions.
			One of our staff members will be happy to contact you directly and answer your questions as soon as possible. 
		</p>
		<form method="post">
        {% csrf_token %}
            {{form.as_p}}
            <!--add the reCAPTCHA Privacy and Terms of Service disclosure-->
            <p>This site is protected by reCAPTCHA and the Google
                <a href="https://policies.google.com/terms">Terms and Conditions</a> apply.
            </p>
            <!--add this reCAPTCHA input-->
            <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response"> 
            <button type="submit">Submit</button>
        </form>
    </div>

 

Add Google reCAPTCHA Privacy Policy link

<!--Contact form-->
	<div style="margin:80px">
		<h1>Contact</h1>
		<h4>Contact us directly if you have any questions</h4>
		<p>
			Please write your name, email address and a message below if you have any questions.
			One of our staff members will be happy to contact you directly and answer your questions as soon as possible. 
		</p>
		<form method="post">
        {% csrf_token %}
            {{form.as_p}}
            <!--add the reCAPTCHA Privacy and Terms of Service disclosure-->
            <p>This site is protected by reCAPTCHA and the Google
                <a href="https://policies.google.com/privacy">Privacy Policy</a> and
                <a href="https://policies.google.com/terms">Terms and Conditions</a> apply.
            </p>
            <!--add this reCAPTCHA input-->
            <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response"> 
            <button type="submit">Submit</button>
        </form>
    </div>

 

View your site's reCAPTCHA data

To view the Google reCAPTCHA information, go to the Admin console at google.com/recaptcha/admin/.

The data is not displayed in real-time, so you will need to wait until the following day to view any information regarding the requests made on your site. 






Post a Comment
Join the community

3 Comments
Priyanshu March 15, 2021, 2:34 a.m.

wtf, why form_valid function is taking 'self' in parameter? where is the class. why super(). to whom you are inheriting? forms? what is message variable? kindly care to explain such thing, we need explanation with code

Jaysha replying to Priyanshu March 15, 2021, 6:10 p.m.

You're right, the code was poorly explained. I have updated the article with more explanation and cleaner reCAPTCHA validation in the views.py. Thanks for the feedback

Bishwas May 14, 2021, 7:36 p.m.

I think you guys wanna check this article too: https://blog.webmatrices.com/django-recaptcha-v3/

2
Jaysha
Written By
Jaysha
Hello! I enjoy learning about new CSS frameworks, animation libraries, and SEO.