Skip to content

Django Module

The myra-eucaptcha-django package integrates EU CAPTCHA into Django forms as a native form field and widget. Configuration is managed through the Django admin or settings.py, and server-side verification is handled automatically on form validation.

  • PyPI: myra-eucaptcha-django
  • License: Proprietary — Copyright 2026 Myra Security GmbH
  • Requires: Python 3.9+, Django 4.2 or 5.0

Installation

pip install myra-eucaptcha-django

Or with uv:

uv add myra-eucaptcha-django

Quick start

1. Add to INSTALLED_APPS

# settings.py
INSTALLED_APPS = [
    ...
    'myra_eucaptcha_django',
]

2. Run migrations

python manage.py migrate

3. Configure credentials

Option A — Django admin (recommended):

Navigate to Django Admin → Captcha Configurations and create a new configuration with your sitekey and secret. Tick Is default to make it the configuration used when no name is specified.

Option B — settings.py:

# settings.py
EUCAPTCHA_SITEKEY = "EUCAPTCHA_SITE_KEY"
EUCAPTCHA_SECRET = "EUCAPTCHA_SECRET_KEY"

Database configurations take precedence over settings.py values when both are present.

4. Add the field to your form

from django import forms
from myra_eucaptcha_django import CaptchaField, CaptchaFormMixin

class ContactForm(CaptchaFormMixin, forms.Form):
    name    = forms.CharField()
    email   = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)
    captcha = CaptchaField()

CaptchaFormMixin forwards the request object to the field so the visitor's IP address is available for verification. It must come before forms.Form in the class bases.

5. Pass the request in your view

from django.shortcuts import render, redirect
from .forms import ContactForm

def contact_view(request):
    if request.method == "POST":
        form = ContactForm(request.POST, request=request)
        if form.is_valid():
            # process the form
            return redirect("success")
    else:
        form = ContactForm()
    return render(request, "contact.html", {"form": form})

6. Render in your template

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Send</button>
</form>

The widget automatically injects the verify.js script tag — no manual <script> tag is needed.

Multiple configurations

Define distinct configurations in the admin (e.g. contact-form, registration) and reference them by name in each form:

class ContactForm(CaptchaFormMixin, forms.Form):
    captcha = CaptchaField("contact-form")

class RegistrationForm(CaptchaFormMixin, forms.Form):
    captcha = CaptchaField("registration")

class CommentForm(CaptchaFormMixin, forms.Form):
    captcha = CaptchaField()  # uses the default configuration

Configuration reference

Core fields

Field Required Default Description
name Unique identifier for this configuration
sitekey Public sitekey for the client-side widget
secret Secret key for server-side verification — never exposed to the browser
description Optional notes on where this configuration is used
is_default False Use this configuration when no config_name is specified
is_active True Allow this configuration to be used

Advanced fields

Field Default Description
verify_url https://api.eu-captcha.eu/v1/verify/ Verification API endpoint
widget_url https://cdn.eu-captcha.eu/verify.js Widget script URL
connect_timeout 3 Connection timeout in seconds
read_timeout 10 Read timeout in seconds
write_timeout 10 Write timeout in seconds
pool_timeout 3 Connection pool timeout in seconds
default_result_on_error True Return success when the API is unreachable (fail-open)
suppress_exceptions True Catch exceptions and return a result instead of raising

settings.py reference

All configuration fields can be set via settings.py as a fallback when no database configuration exists:

EUCAPTCHA_SITEKEY                = "EUCAPTCHA_SITE_KEY"
EUCAPTCHA_SECRET                 = "EUCAPTCHA_SECRET_KEY"
EUCAPTCHA_VERIFY_URL             = "https://api.eu-captcha.eu/v1/verify/"
EUCAPTCHA_WIDGET_URL             = "https://cdn.eu-captcha.eu/verify.js"
EUCAPTCHA_CONNECT_TIMEOUT        = 3
EUCAPTCHA_READ_TIMEOUT           = 10
EUCAPTCHA_WRITE_TIMEOUT          = 10
EUCAPTCHA_POOL_TIMEOUT           = 3
EUCAPTCHA_DEFAULT_RESULT_ON_ERROR = True
EUCAPTCHA_SUPPRESS_EXCEPTIONS    = True

API reference

CaptchaField

CaptchaField(config_name=None, **kwargs)

A Django form field that renders the widget and validates the token on form.is_valid(). Pass a config_name to use a specific named configuration; omit it to use the default.

CaptchaFormMixin

Mixin that automatically passes request to captcha fields so the visitor's IP is available during verification. Always place it before forms.Form in the class bases:

class MyForm(CaptchaFormMixin, forms.Form):
    captcha = CaptchaField()

Instantiate the form with request=request in your view:

form = MyForm(request.POST, request=request)

validate_captcha

Low-level validation for cases where you are not using a form field:

from myra_eucaptcha_django import validate_captcha

validate_captcha(
    token="eu-captcha-response value",
    remote_addr="VISITOR_IP",   # optional
    config_name="my-config",   # optional, uses default if omitted
)

Raises django.core.exceptions.ValidationError on failure.

Fault tolerance

The default_result_on_error and suppress_exceptions options behave the same as in the Python module: by default the package fails open on network errors so legitimate users are not blocked during API outages. Set default_result_on_error = False for high-security endpoints where you prefer to reject submissions when the API is unreachable.