Catalogue & product data
CAPTCHA Integration
This ships in the core. It is implemented in src/pages/captcha.js.ts. What follows is the plan it was built from, kept as written — the shipped code may go further than it, or differ in the details.
Core infrastructure for protecting forms (newsletter, contact, inquiry, checkout) from bot spam using reCAPTCHA v3 or hCaptcha. Configurable by merchant (API key + secret), integrated into all form endpoints. This is foundational; spam filtering beyond CAPTCHA belongs in a paid tier.
The problem
Merchants get flooded with spam submissions from bots; form data becomes unusable noise.
What it does
- CAPTCHA provider choice: reCAPTCHA v3 or hCaptcha, merchant configurable
- Client-side token generation: CAPTCHA is rendered on form page, generates token on submit
- Server-side verification: POST endpoint verifies token against CAPTCHA API, rejects if score below threshold (reCAPTCHA) or verification fails (hCaptcha)
- Configurable settings: API key, secret key, verification score threshold (reCAPTCHA only, default 0.5), form types (newsletter, contact, inquiry, all)
- Fallback behavior: if CAPTCHA API is unreachable, allow form submission (fail-open) or reject (fail-closed, configurable)
- Rate limiting per IP: track CAPTCHA failures per IP, throttle if too many failures in short time
- Admin panel: CAPTCHA settings page (provider, API keys, threshold, form types), test CAPTCHA connection
- Form-specific control: merchant can enable/disable CAPTCHA per form (e.g., CAPTCHA on newsletter but not contact)
- Webhook on CAPTCHA bypass: if verification fails, emit event for plugins to log security incident
- Privacy compliance: reCAPTCHA v3 uses no user interaction (transparent); hCaptcha is merchant-controlled, compliant with GDPR/privacy laws
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- Custom CAPTCHA challenges (math, image recognition) — use industry-standard providers only
- IP-based blocking or allow-listing — that’s firewall/network tier; CAPTCHA is form-level
- Behavioral analysis (mouse movement, typing patterns) — that’s bot detection, not CAPTCHA
- CAPTCHA bypass detection via ML — defer to CAPTCHA provider’s abuse detection
Data model
New entity (or plugin key-value store): captcha_config (provider: ‘recaptcha_v3’ | ‘hcaptcha’, api_key: encrypted string, secret_key: encrypted string, threshold: float (reCAPTCHA only), fail_closed: boolean, enabled_for_forms: array of form types [‘newsletter’, ‘contact’, ‘inquiry’, ‘checkout’]).
API
- POST /captcha/verify — accept {provider, token, ip_address}, return {verified: boolean, score?: float (reCAPTCHA), error?: string}
- GET /captcha/config — retrieve current CAPTCHA settings (admin only)
- PUT /captcha/config — update CAPTCHA settings (admin only)
- POST /captcha/test — verify connection to CAPTCHA provider (admin only), return {connected: boolean, latency_ms: integer}
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
CAPTCHA settings panel: (1) Provider selector (reCAPTCHA v3 or hCaptcha), (2) API key and secret fields (show/hide toggle), (3) Threshold slider (reCAPTCHA only), (4) Fail-closed vs fail-open toggle, (5) Form type checklist (enable/disable CAPTCHA per form), (6) Test connection button, (7) Docs link with API key setup instructions.
The seam — why this is core
Core owns CAPTCHA integration and verification logic. This is foundational spam protection. Paid tier could own advanced spam filtering (keyword matching, sender reputation), IP-based blocking/allow-listing, and behavioral bot detection (fails at form-level; analytics for abuse patterns belong in a security plugin).
Core owns the interface + honest hCaptcha/reCAPTCHA wrapper; bot protection is infrastructure, not a per-country obligation or credential.
Dependencies
- form-system (core; CAPTCHA is integrated into all form types: newsletter, contact, inquiry)
- email-layer (core; to send CAPTCHA setup instructions/reminders)
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- Merchant configures reCAPTCHA v3 with API key and secret, sets threshold to 0.7. A POST /newsletter/subscribe includes captcha_token.
- POST /captcha/verify is called with token and IP address; if score >= 0.7, subscription proceeds; if score < 0.7, request is rejected.
- hCaptcha is selected as provider; POST /captcha/verify verifies token against hCaptcha API. If verification succeeds, form proceeds.
- With fail_closed=true and CAPTCHA API unreachable, form submissions are rejected. With fail_closed=false, submissions are allowed.
- Merchant enables CAPTCHA for ‘newsletter’ and ‘contact’ forms only; ‘inquiry’ forms do not require CAPTCHA.
- POST /captcha/test returns {connected: true, latency_ms: 250} indicating CAPTCHA provider is reachable.
- Three failed CAPTCHA verifications from the same IP within 5 minutes trigger rate limiting; next attempt is rejected for 10 minutes.
- reCAPTCHA v3 score is logged but not shown to user (transparent); hCaptcha checkbox is shown to user.
Risks
If API keys are leaked or misconfigured, bots can bypass CAPTCHA. If fail-open is enabled and CAPTCHA API fails, spam floods in. If threshold is too high, legitimate users are rejected; too low, bots pass. Migrating from one CAPTCHA provider to another requires updating all client-side code (form HTML/JS). If CAPTCHA endpoint is rate-limited by the provider, form submissions fail silently.
Commercial context
| Suggested price | free (core) |
| Rival anchor | Shopify: included; Magento: included |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and CONTRIBUTING.md for how to work on this repository.