Drupal Module
The EU CAPTCHA Drupal module integrates the EU CAPTCHA widget and server-side verification into your Drupal site with no custom code required. It supports Drupal core forms and several popular contributed modules out of the box.
- Version: 1.0.0
- Requires: Drupal 10+ or 11+, PHP 8.1+
- License: BSD-2-Clause
- Download: eu_captcha.zip
Supported forms
| Form | Module required |
|---|---|
| Drupal User Login | — |
| Drupal User Registration | — |
| Drupal Password Reset | — |
| Comments | — |
| Contact Forms | Core Contact module |
| Webform submissions | Webform module |
| Content (Node) Forms | — |
We are happy to include support for more form types. Please contact support if you need additional destinations covered.
Installation
Option A — Upload via admin UI
- Download eu_captcha.zip.
- Go to Extend → Add new module and upload the zip file, or extract the
eu_captchafolder toweb/modules/custom/. - Go to Extend, find EU-Captcha under the Security package, and enable it.
Option B — Drush
drush en eu_captcha
drush cr
After enabling, go to Configuration → System → EU-Captcha Settings (/admin/config/system/eu-captcha) to configure the module.
Configuration
Quick Setup
Click Quick Setup on the settings page. A modal opens loading the EU CAPTCHA dashboard in an embedded iframe. Complete the registration flow inside the modal — the module receives your sitekey and secret automatically via postMessage and saves them without you copying anything.
If you are on a different admin page, clicking Quick Setup in the notice bar navigates you to the settings page and opens the modal automatically.
Manual credentials
If you already have a sitekey and secret from the dashboard, enter them directly in the API Settings section.
| Field | Description |
|---|---|
| Public Sitekey | Your public sitekey (UUID format). Safe to display on the frontend. |
| Secret | Your secret key (Base64 format). Stored in Drupal configuration — never sent to the browser. The field is never pre-filled; leave it blank to keep the stored value. |
Protected destinations
Check each form type you want to protect. The widget is injected and server-side verification is enforced only for the destinations you enable.
| Destination | Description |
|---|---|
user_login |
Drupal user login form |
user_register |
Drupal user registration form |
user_pass |
Drupal password reset form |
comment |
Comment forms for any content type |
contact |
Core Contact module forms |
webform |
Webform module submission forms |
node |
Node add/edit forms for any content type |
API options
| Option | Default | Description |
|---|---|---|
| Check CDN / Proxy Headers | On | When enabled, the module reads the visitor's real IP from HTTP_CLIENT_IP, X-Forwarded-For, or X-Real-IP before falling back to the request IP. Enable this if your site sits behind a CDN or load balancer. |
| Failsafe | Off | When disabled (default), a network error reaching the verification API causes the form submission to be blocked. When enabled, transport-level errors (timeouts, DNS failures) are treated as a passed verification so submissions go through. Invalid tokens are still rejected regardless of this setting. |
Widget Styling
| Option | Default | Description |
|---|---|---|
| Theme | Light | Controls the widget colour scheme. Choose Light or Dark. |
| Height (px) | — | Optional fixed height in pixels (minimum 48). Leave empty to use the widget default. |
| Width (px) | — | Optional fixed width in pixels (minimum 1). Leave empty to use the widget default. |
Save & Test
Use the Save & Test button to save your credentials and immediately run a live API call to verify that the sitekey and secret are correct.
Permissions
| Permission | Description |
|---|---|
administer eu captcha |
Grants access to the settings page and dismissal of the admin notice. Assign to trusted administrators only. |
How it works
- The module loads
https://cdn.eu-captcha.eu/verify.js(withasync defer) on every page where a protected form is rendered. - It injects
<div class="eu-captcha" data-sitekey="...">inside each enabled form viahook_form_alter. - On form submission, it reads
eu-captcha-responsefrom the POST data and sends a server-side request tohttps://api.eu-captcha.eu/v1/verifywith the token, visitor IP, and User-Agent. - Submissions are accepted or rejected based on the API response. Errors are logged to the Drupal watchdog (
eu_captchachannel).
Custom integration
If you want to protect a form that the module does not handle natively, call the helper functions directly.
1. Render the widget in your form:
function mymodule_form_my_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
_eu_captcha_attach_widget($form);
$form['#validate'][] = '_eu_captcha_validate_token';
}
_eu_captcha_attach_widget() adds the <div class="eu-captcha" ...> element and enqueues verify.js. _eu_captcha_validate_token() is the standard form validation callback that checks the submitted token.
2. Verify a token manually:
$token = \Drupal::request()->request->get('eu-captcha-response', '');
$passed = _eu_captcha_verify_token((string) $token);
if (!$passed) {
// reject the submission
}
_eu_captcha_verify_token() returns true on success and false on failure. On network error it returns the value of the Failsafe setting.
Third-party services
The module communicates with the following external hosts:
| Host | Purpose |
|---|---|
cdn.eu-captcha.eu |
Loads verify.js on pages with protected forms |
api.eu-captcha.eu |
Server-side token verification on each form submission |
app.eu-captcha.eu |
EU CAPTCHA dashboard loaded in the Quick Setup iframe |
EU CAPTCHA sets no cookies and collects no personal data in the browser, making it GDPR-compliant without a cookie banner. Data sent to api.eu-captcha.eu on each verification: sitekey, secret, captcha response token, visitor IP address, visitor User-Agent string. Refer to the EU CAPTCHA Privacy Policy for details on how this data is processed.
Troubleshooting
The widget does not appear on a form
- Confirm the destination is ticked under Protected Destinations and that you clicked Save Changes.
- Check that the sitekey is saved and in valid UUID format. The settings page shows a ✅ / ❌ indicator next to the field.
- Open browser DevTools → Network and verify that
verify.jsloaded without errors. - If a Content Security Policy is active, add
cdn.eu-captcha.eutoscript-srcandconnect-src.
Form submissions are blocked even for real users
- Verify the sitekey and secret are correct using Save & Test.
- Check that the sitekey was created for this domain. Each sitekey is tied to the domain specified at creation — create a new sitekey if needed.
Submissions always pass even for empty tokens
- Confirm the secret is correct. A wrong secret puts the API into bypass mode (
train: true) where all submissions appear successful.
The module blocks all submissions when your CDN is active
- Enable Check CDN / Proxy Headers in API Settings so the module forwards the real visitor IP rather than the CDN's address.
After saving settings, the secret field is empty
- This is expected. Drupal password fields are never pre-filled for security reasons. Leaving the field blank preserves the stored secret — only enter a value when you want to change it.
What happens during an EU CAPTCHA outage?
By default the module blocks submissions when the API is unreachable (fail closed). Enable Failsafe to accept submissions during outages (fail open). See the Failsafe option above.