therealworld / formrecaptchav3-module
A Google-Recaptcha-V3-Module for public forms like contact-form in OXID7.
Package info
bitbucket.org/therealworld/formrecaptchav3-module
Type:oxideshop-module
pkg:composer/therealworld/formrecaptchav3-module
Requires
- php: ^8.3
- ext-json: *
- oxid-esales/oxideshop-ce: >=v7.4
- therealworld/tools-plugin: >=v3.3
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- v2.x-dev
- v2.0.20
- v2.0.19
- v2.0.18
- v2.0.17
- v2.0.16
- v2.0.15
- v2.0.14
- v2.0.13
- v2.0.12
- v2.0.11
- v2.0.10
- v2.0.9
- v2.0.8
- v2.0.7
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.3.16
- v1.3.15
- v1.3.14
- v1.3.13
- v1.3.12
- v1.3.11
- v1.3.10
- v1.3.9
- v1.3.8
- v1.3.7
- v1.3.6
- v1.3.5
- v1.3.4
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- dev-master
This package is auto-updated.
Last update: 2026-10-26 07:34:43 UTC
README
Deutsche Fassung: README.de.md

description
Protects the shop's public forms with an invisible Google reCAPTCHA v3. The visitor sees no challenge: the page loads Google's script, which puts a token into a hidden field of the form. On submit the module has Google verify the token and rejects the submission if Google does not confirm it or the score is too low.
Protected forms (each can be switched on/off separately):
- registration (
UserComponent::createUser()) and invitation (InviteController::send()) - newsletter subscription (
NewsletterController::send()) - contact form (
ContactController::send()) - price alarm on the detail page and on the price alarm page (
ArticleDetailsController::addMe(),PriceAlarmController::addme()) - forgot password (
ForgotPasswordController::forgotPassword()) - forms of other modules that use the FormGuard contract of
therealworld/tools-plugin(for example the withdrawal form oftherealworld/withdrawal-module)
A rejected submission is simply not carried out: no mail, no account, no newsletter subscription, no price alarm.
Alternative without Google:
therealworld/captcha-module(module idtrwcaptcha) protects the same forms with local checks only (honeypot, dwell time, proof of work, image challenge) and needs no keys and no external API. It plugs into the same FormGuard contract.
requirements
- OXID eShop CE
>=v7.4, PHP^8.3,ext-json therealworld/tools-plugin>=v3.3(brings the FormGuard contract this module decorates)- a reCAPTCHA v3 key pair (site key + secret key) from Google
installation
- composer package:
therealworld/formrecaptchav3-module - OXID module id:
trwformrecaptchav3
composer require therealworld/formrecaptchav3-module
vendor/bin/oe-console oe:module:activate trwformrecaptchav3
With therealworld/clirun-plugin installed, vendor/bin/oe-console trw:module:setup trwformrecaptchav3
does the same in one step.
configuration
Admin: Extensions > Modules > the-real-world - Form Google ReCaptcha V3 Protection > Settings.
Google Recaptcha v3 API
| Option (admin) | Setting | Default | Effect |
|---|---|---|---|
| Website Key | sTRWFormReCaptchaV3WebsiteKey | empty | public site key, used to load Google's script in the frontend |
| Secret Key | sTRWFormReCaptchaV3SecretKey | empty | secret key, used for the server-side verification |
| Spam Score | sTRWFormReCaptchaV3Score | 0.5 | threshold 0.0-1.0; a submission with a score below this value is rejected, a score equal to it passes |
Controlling
| Option (admin) | Setting | Default | Effect |
|---|---|---|---|
| use Google ReCaptcha v3 Protection | bTRWFormReCaptchaV3UseReCaptchaV3 | off | master switch; nothing is rendered or checked while it is off |
| Show in the frontend an error message ... | bTRWFormReCaptchaV3ThrowMessageOnError | off | shows "The form was misused and therefore not sent." on a rejected submission |
| Generate "Error"-logs if someone has fallen into the recaptchav3 | bTRWFormReCaptchaV3ThrowExceptionOnError | on | writes an error entry for every rejected submission |
| Generate "Use"-log for register forms / newsletter form / contact form / detail page forms (pricealarm) / forgot password form | bTRWFormReCaptchaV3WriteLogForUser, ...Newsletter, ...Contact, ...Details, ...Password | off | writes an info entry for every submission of that form group, passed or rejected |
| Should the IP be logged? | bTRWFormReCaptchaV3CollectIP | off | adds the client IP to the log entries; clarify with your data protection officer |
If the website key or the secret key is empty, the check is skipped and every submission passes; a warning is written to the module log (see below).
Integrations
| Option (admin) | Setting | Default | Covers |
|---|---|---|---|
| Add to register forms? | bTRWFormReCaptchaV3IntegrationUser | on | registration, invitation |
| Add to newsletter form? | bTRWFormReCaptchaV3IntegrationNewsletter | on | newsletter |
| Add to conctact form? | bTRWFormReCaptchaV3IntegrationContact | off | contact |
| Add to detail page forms (pricealarm)? | bTRWFormReCaptchaV3IntegrationDetails | off | price alarm |
| Add to forgot password form? | bTRWFormReCaptchaV3IntegrationPassword | off | forgot password |
| Add to forms of other modules? | bTRWFormReCaptchaV3IntegrationExternalForms | on | all forms of other modules registered through the FormGuard contract |
There is also a hidden setting aTRWFormReCaptchaV3ExternalControllers (form key => reCAPTCHA action)
that other modules fill on activation (the withdrawal-module registers its form there). An entry
overrides the "forms of other modules" switch for that one form; the value off switches it off.
It has no field in the admin; to change it by hand, edit it in
var/configuration/shops/<shop-id>/modules/trwformrecaptchav3.yaml and reactivate the module.
logging
Log file: log/trwformrecaptchav3/YYYY-MM-DD.log in the shop's log directory (not oxideshop.log).
!Form abuse! Data: ...(error) - rejected submission, if the error log switch is on!Form usage! Data: ...(info) - every submission of a form group whose "Use"-log switch is on!ReCaptcha V3 is switched on, but the website key or the secret key is missing ...(warning) - the module is switched on without keys and lets the submission pass unchecked (once per request)
Each entry contains the controller, Google's answer (Score, Success, Errors = Google's
error-codes, Action, Host, Time), optionally the IP, and the submitted form data
(invadr, pa, editval, lgn_usr, or the fields a foreign form hands over). Google's
error-codes are the only diagnosis when a verification fails (e.g. invalid-input-secret,
timeout-or-duplicate).
Note: the "Use"-logs store customers' form input (personal data). They are off by default; switch them on for debugging only and off again afterwards.
limits / known caveats
- The verification runs inside the form submit with a 10 second timeout. If Google cannot be reached, the answer counts as "not verified" and the submission is rejected.
- Missing keys are caught (check skipped, warning logged), a wrong secret key is not: Google
answers
invalid-input-secretand every protected form is rejected. Check the log after setup. - If Google's script is blocked (ad blocker, consent tool, CSP), the token field stays empty and the submission is rejected.
- The markup is added through the Twig blocks
captcha_form(contact, price alarm, invitation),form_user_billing_country(registration),newsletter_form_captchaandforgotpwd_email_form. A theme without these blocks gets no token and therefore rejects the forms.
for developers
- Chain extensions:
ViewConfig,UserComponent,ArticleDetailsController,ContactController,ForgotPasswordController,InviteController,NewsletterController,PriceAlarmController. - Verification:
Core\FormReCaptchaV3Helper::checkReCaptchaV3($controller, $writeLog, $formElements)returnstrueif the submission is to be rejected. It callshttps://www.google.com/recaptcha/api/siteverifyviaToolsApi(file_get_contents whenallow_url_fopenis on, otherwise Guzzle). - FormGuard:
Service\FormGuarddecoratesTheRealWorld\ToolsPlugin\Contract\FormGuardInterface(decoration_priority: 20) and only handles form keys that are not the shop's own (FormKey::getShopFormKeys()); those are covered by the chain extensions. Results are merged with the inner guard, so several captcha modules can protect the same form. Exceptions while rendering or verifying are logged to the OXID log and let the form pass. - ViewConfig:
integrateReCaptchaV3(),getTRWFormReCaptchaV3UseReCaptcha(),getTRWFormReCaptchaV3WebsiteKey(). - Templates:
@trwformrecaptchav3/frontend/formrecaptchav3.html.twig(shop forms, usesoViewConfandscript()),@trwformrecaptchav3/frontend/formrecaptchav3_guard.html.twig(foreign forms, plain script tags). The token is refreshed every 60 seconds. - No database tables, no migrations, no CLI commands.