Admin sidebar -> MMKreativ Plugins -> ALTCHA spam protection. One settings entry per channel - this is not a global switch.
| Setting | Meaning |
|---|---|
| Enable | Switches ALTCHA on for the channel. A channel without an entry is unprotected and its challenge endpoint answers 404. |
| Protected forms | Every ticked form requires a solved proof, except the checkout sign-in, which is rate-limit only. A ticked form whose template does not render the widget rejects every submission - see Storefront Integration. |
| Proof-of-work cost / attempts | Difficulty. Cost is capped at 100,000 (the server pays it once per challenge); cost x attempts is capped at 100 million, above which no browser could solve it in reasonable time. |
| Challenge lifetime | How long a solved challenge stays valid. |
| Rate limit | Attempts per client address and form within a window. |
| Honeypot / minimum fill time | Advisory extra layers: fill time is only checked when the browser sent a valid signed timestamp, so a bot that omits the field skips that layer but never the proof. |
| Reject disposable-mail addresses | Off by default - see Practical Examples. |
| Reject / log gibberish text | Off by default; reject from score 85, log from score 60 - see Practical Examples. |
| Generate a new secret | Rotates the channel's HMAC secret. Created on first save, never displayed again. |
If
APP_SECRETchanges, every protected form, including the login, is rejected until you open each channel and tick "Generate a new secret" - it fails closed on purpose. All application servers must share the sameAPP_SECRET.
The targets this plugin renders a widget for (registration, contact, login, forgotten password) and the checkout sign-in (which needs none) start ticked. The sibling-plugin and custom-form targets start unticked: enforcing them before their template renders the widget would reject every submission.
| Grid | Reached via | Purpose |
|---|---|---|
| ALTCHA spam protection (channel settings) | Sidebar entry | One row per channel; create/edit/delete the settings above |
| ALTCHA custom forms | Button on channel settings | Register a plugin's or your own form type as an additional protection target (custom_ code prefix) |
| ALTCHA disposable-mail overrides | Button on channel settings | Allow/deny entries on top of the bundled disposable-domain snapshot |
| ALTCHA blocked domains | Button on disposable-mail overrides | Read-only, searchable list of every domain currently blocked (snapshot + your deny entries) |
| ALTCHA gibberish log | Button on channel settings | Read-only log of flagged submissions: time, channel, form, result, score, reasons - never the submitted text |
The channel-settings and custom-target grids are full CRUD (ResourceBundle); the blocked-domains list and the gibberish log are read-only.
1. Protect a channel's contact and registration forms only, leave checkout sign-in unprotected. Enable the channel, tick contact and registration, leave the checkout-login target unticked. Keep the proof-of-work cost at its default - no widget placement needed, both are built-in targets.
2. Roll out the gibberish check safely on a channel that gets contact-form spam. Tick "Reject meaningless free text", but first set the reject score to 100 (so nothing is actually blocked yet). Watch the ALTCHA gibberish log for a week. Once what is logged there is clearly spam, lower the reject score toward the default 85.
3. Add a custom checkout-note form as a protection target. Admin -> ALTCHA spam protection -> ALTCHA custom forms -> add the form type class and a code, for example custom_checkout_note. Place {{ mmd_altcha_widget('custom_checkout_note') }} once in that form's template (see Storefront Integration), then tick the target in the channel settings.
4. Allow-list a relay address wrongly caught by the disposable-mail check. Admin -> ALTCHA spam protection -> ALTCHA disposable-mail overrides -> add an Allow entry for the domain (for example a SimpleLogin or Hide-My-Email relay domain). An allow entry always wins, even over a denied parent domain.