Search by

therealworld / formrecaptchav3-module

therealworld

A Google-Recaptcha-V3-Module for public forms like contact-form in OXID7.

Package info

bitbucket.org/therealworld/formrecaptchav3-module

Homepage

Issues

Type:oxideshop-module

pkg:composer/therealworld/formrecaptchav3-module

Statistics

Installs: 13 232

Dependents: 0

Suggesters: 0

v2.0.20 2026-10-25 12:22 UTC

README

Deutsche Fassung: README.de.md

vendor-logo the-real-world.de

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 of therealworld/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 id trwcaptcha) 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)SettingDefaultEffect
Website KeysTRWFormReCaptchaV3WebsiteKeyemptypublic site key, used to load Google's script in the frontend
Secret KeysTRWFormReCaptchaV3SecretKeyemptysecret key, used for the server-side verification
Spam ScoresTRWFormReCaptchaV3Score0.5threshold 0.0-1.0; a submission with a score below this value is rejected, a score equal to it passes

Controlling

Option (admin)SettingDefaultEffect
use Google ReCaptcha v3 ProtectionbTRWFormReCaptchaV3UseReCaptchaV3offmaster switch; nothing is rendered or checked while it is off
Show in the frontend an error message ...bTRWFormReCaptchaV3ThrowMessageOnErroroffshows "The form was misused and therefore not sent." on a rejected submission
Generate "Error"-logs if someone has fallen into the recaptchav3bTRWFormReCaptchaV3ThrowExceptionOnErroronwrites an error entry for every rejected submission
Generate "Use"-log for register forms / newsletter form / contact form / detail page forms (pricealarm) / forgot password formbTRWFormReCaptchaV3WriteLogForUser, ...Newsletter, ...Contact, ...Details, ...Passwordoffwrites an info entry for every submission of that form group, passed or rejected
Should the IP be logged?bTRWFormReCaptchaV3CollectIPoffadds 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)SettingDefaultCovers
Add to register forms?bTRWFormReCaptchaV3IntegrationUseronregistration, invitation
Add to newsletter form?bTRWFormReCaptchaV3IntegrationNewsletteronnewsletter
Add to conctact form?bTRWFormReCaptchaV3IntegrationContactoffcontact
Add to detail page forms (pricealarm)?bTRWFormReCaptchaV3IntegrationDetailsoffprice alarm
Add to forgot password form?bTRWFormReCaptchaV3IntegrationPasswordoffforgot password
Add to forms of other modules?bTRWFormReCaptchaV3IntegrationExternalFormsonall 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-secret and 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_captcha and forgotpwd_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) returns true if the submission is to be rejected. It calls https://www.google.com/recaptcha/api/siteverify via ToolsApi (file_get_contents when allow_url_fopen is on, otherwise Guzzle).
  • FormGuard: Service\FormGuard decorates TheRealWorld\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, uses oViewConf and script()), @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.