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.