Skip to content

Django CAPTCHA Integration

This recipe shows how to integrate TrustCaptcha into a Django application. The frontend setup is the same as for any other Python application — this page focuses on the server-side validation.

The setup section gets you to a working integration in three small steps using a view function directly. Below it, an optional refactor section shows the more reusable Django-idiomatic approach (a Form class with a custom clean() method).

You should have already completed the following steps before you wire TrustCaptcha into your Django application.

  1. Read Get-Started: Get a quick overview of the concepts behind TrustCaptcha and the integration process in get started.

  2. Existing CAPTCHA: If you don’t have a CAPTCHA yet, sign in or create a new user account. Then create a new CAPTCHA.


First, add the TrustCaptcha script to your page (see the JavaScript Guide for version pinning and self-hosting options).

Then place the <trustcaptcha-component> element inside your Django template form. The widget appends a hidden tc-verification-token field on submit, which your view receives in request.POST like any other form input.

templates/contact.html
<script type="module" src="https://cdn.trustcomponent.com/trustcaptcha/3.0.x/trustcaptcha.esm.min.js"></script>
<form method="post" action="{% url 'contact_submit' %}">
{% csrf_token %}
<label>Email</label>
<input type="email" name="email" required>
<trustcaptcha-component sitekey="<your_site_key>"></trustcaptcha-component>
<button type="submit">Send</button>
</form>

See the Widget Overview for the full property reference.

Terminal window
pip install "trustcaptcha>=3.0.0,<4.0.0"
contact/views.py
from django.shortcuts import redirect, render
from django.views.decorators.http import require_POST
from trustcaptcha.trust_captcha import TrustCaptcha
@require_POST
def submit(request):
# In production, load from settings: settings.TRUSTCAPTCHA_API_KEY
api_key = "<your_api_key>"
token = request.POST.get("tc-verification-token", "")
try:
trust_captcha = TrustCaptcha(api_key)
result = trust_captcha.get_verification_result(token)
except Exception:
return render(request, "contact.html", {"error": "CAPTCHA verification failed."})
if not result.verification_passed or result.score > 0.5:
return render(request, "contact.html", {"error": "CAPTCHA verification failed."})
# CAPTCHA passed — request data is safe to use.
# ... your business logic ...
return redirect("contact_success")

That’s it — the form is now protected. For real deployments, move the API key out of the source code (see the comment) and consider explicit failover handling — see Failover Behavior for the reasoning and a code template.


If you protect more than one view, the most idiomatic Django approach is to validate the token inside a forms.Form class. The verification call then becomes part of normal form validation, reusable across views and reachable through form.is_valid().

myproject/settings.py
import os
TRUSTCAPTCHA_API_KEY = os.environ["TRUSTCAPTCHA_API_KEY"]
contact/forms.py
from django import forms
from django.conf import settings
from trustcaptcha.trust_captcha import TrustCaptcha
class ContactForm(forms.Form):
email = forms.EmailField()
tc_verification_token = forms.CharField(widget=forms.HiddenInput, required=True)
def clean_tc_verification_token(self):
token = self.cleaned_data["tc_verification_token"]
try:
trust_captcha = TrustCaptcha(settings.TRUSTCAPTCHA_API_KEY)
result = trust_captcha.get_verification_result(token)
except Exception:
raise forms.ValidationError("CAPTCHA verification failed.")
if not result.verification_passed or result.score > 0.5:
raise forms.ValidationError("CAPTCHA verification failed.")
return token

The form field is named tc_verification_token (underscore) because Python identifiers can’t contain dashes. To keep the wire format unchanged (the widget posts tc-verification-token), add a prefix-less custom binding — see Notes below — or set token-field-name="tc_verification_token" on the widget.

contact/views.py
from django.shortcuts import redirect, render
from .forms import ContactForm
def submit(request):
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
# CAPTCHA already verified
# ... your business logic ...
return redirect("contact_success")
else:
form = ContactForm()
return render(request, "contact.html", {"form": form})

Errors raised in clean_tc_verification_token automatically appear in the bound form’s errors dictionary, just like any other validation error.


CSRF. Django’s CSRF protection ({% csrf_token %} and the middleware) and TrustCaptcha are independent layers — both should stay enabled. The CAPTCHA token does not replace the CSRF token.

Field name. Python identifiers can’t contain dashes, so the form field is tc_verification_token. The simplest fix is to set token-field-name="tc_verification_token" on the widget so the wire format matches the form field. Alternatively, manually copy the value from request.POST["tc-verification-token"] into the form data before instantiating the form.

Async views. The Python SDK is blocking. Inside an async view, wrap the verification in sync_to_async so the event loop stays responsive: result = await sync_to_async(trust_captcha.get_verification_result)(token).

Configured SDK options. For custom timeouts, proxy, or a custom API host, pass them to the constructor: TrustCaptcha(api_key, api_host=..., proxy=...). See the Python Guide for the full constructor options.


Once you have wired TrustCaptcha into your Django application, you can use TrustCaptcha to its full extent. However, we still recommend the following additional technical and organizational measures:

  • Security rules: You can find many security settings for your CAPTCHA in the CAPTCHA settings. These include, for example, authorized websites, CAPTCHA bypass for specific IP addresses, bypass keys, IP based blocking, geoblocking, individual difficulty and duration of the CAPTCHA, and much more. Learn more about the security rules.

  • Privacy & GDPR compliance: Include a passage in your privacy policy that refers to the use of TrustCaptcha. We also recommend that you enter into a data processing agreement with us to stay GDPR-compliant. Learn more about data protection.

  • Accessibility & UX: Customize TrustCaptcha to your website so that your website is as accessible as possible and offers the best possible user experience. More about accessibility.

  • Failover behavior: Decide how your backend should behave when our service is temporarily unreachable. This is particularly important for high-availability flows where blocking real users during an outage is worse than letting through a small amount of unverified traffic. Learn more about failover behavior.

  • Testing: If you use automated testing, make sure that the CAPTCHA does not block it. Learn more about testing.