Skip to content

How to integrate Magento 2 native CAPTCHA into a custom frontend form?

I’m working on Magento 2.4.x and I want to integrate Magento’s native CAPTCHA functionality into a custom frontend form for better security. I’ve seen CAPTCHA being used on the customer login and registration forms, but I’m unsure how to implement it in my custom form.

Here’s what I’ve done so far:

  1. Created the custom form:
    I’ve built a custom form accessible via a new frontend route. The form submits data to a custom controller. Here’s the basic form structure:

    <form id="custom_form" action="<?= $block->getUrl('customroute/submit') ?>" method="post">
        <input type="text" name="name" placeholder="Name">
        <input type="email" name="email" placeholder="Email">
        <!-- CAPTCHA should be added here -->
        <button type="submit">Submit</button>
    </form>
    
  2. Updated di.xml to add the form ID for CAPTCHA validation:

    <type name="MagentoCaptchaModelDefaultCaptcha">
        <arguments>
            <argument name="forms" xsi:type="array">
                <item name="custom_form" xsi:type="string">custom_form</item>
            </argument>
        </arguments>
    </type>
    
  3. Added CAPTCHA block to the layout XML:

    <referenceContainer name="form.additional.info">
        <block class="MagentoCaptchaBlockCaptcha" name="custom_form_captcha" cacheable="false">
            <arguments>
                <argument name="formId" xsi:type="string">custom_form</argument>
                <argument name="imgWidth" xsi:type="number">230</argument>
                <argument name="imgHeight" xsi:type="number">50</argument>
            </arguments>
        </block>
    </referenceContainer>
    
  4. Added CAPTCHA validation in the controller:

    use MagentoCaptchaHelperData as CaptchaHelper;
    use MagentoFrameworkAppActionAction;
    use MagentoFrameworkAppActionContext;
    use MagentoFrameworkControllerResultJsonFactory;
    
    class Submit extends Action
    {
        private $captchaHelper;
        private $jsonFactory;
    
        public function __construct(
            Context $context,
            CaptchaHelper $captchaHelper,
            JsonFactory $jsonFactory
        ) {
            parent::__construct($context);
            $this->captchaHelper = $captchaHelper;
            $this->jsonFactory = $jsonFactory;
        }
    
        public function execute()
        {
            $formId = 'custom_form';
            $captchaModel = $this->captchaHelper->getCaptcha($formId);
            $post = $this->getRequest()->getPostValue();
    
            if (!$captchaModel->isCorrect($post['captcha'])) {
                $result = $this->jsonFactory->create();
                return $result->setData(['error' => true, 'message' => __('Invalid CAPTCHA.')]);
            }
    
            // Process form data
            $result = $this->jsonFactory->create();
            return $result->setData(['success' => true, 'message' => __('Form submitted successfully.')]);
        }
    }
    

What I need help with:

  1. Adding the CAPTCHA to the form frontend:
    How do I properly render the CAPTCHA in the form using the layout and Captcha block?

  2. Handling CAPTCHA validation in the controller:
    Am I missing anything in the controller logic to validate the CAPTCHA?

  3. Refreshing the CAPTCHA image:
    How do I include the “refresh CAPTCHA” functionality like in Magento’s customer forms?

If someone could guide me or provide a full example of integrating native Magento CAPTCHA into a custom frontend form, I’d really appreciate it!