Development of a 1C-Bitrix feedback module

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Feedback Module Development for 1C-Bitrix

The standard bitrix:main.feedback component can send an email and save a record to an infoblock. This is sufficient for a landing page with a single form. As soon as there are multiple forms with different fields, department routing, CRM integration, anti-spam, and a conversion dashboard — the standard solution breaks down. A feedback module is a full-featured form management system with analytics.

Data Model

Module vendor.feedback:

  • b_vendor_feedback_form — forms: id, code, name, fields_schema (JSON), submit_action (JSON: email/crm/webhook), success_message, redirect_url, is_active, spam_protection (JSON)
  • b_vendor_feedback_submission — submissions: id, form_id, data (JSON), user_id, ip, user_agent, page_url, utm_source, utm_medium, utm_campaign, status (new/processed/spam), created_at
  • b_vendor_feedback_attachment — submission file attachments: id, submission_id, file_id
  • b_vendor_feedback_stat — form statistics (daily snapshots): form_id, date, views, submissions, conversion

Form Builder

The form field schema is stored in fields_schema as JSON. Example:

[
  {"type": "text",   "name": "name",    "label": "Name",       "required": true},
  {"type": "phone",  "name": "phone",   "label": "Phone",      "required": true, "mask": "+7 (999) 999-99-99"},
  {"type": "email",  "name": "email",   "label": "Email",      "required": false},
  {"type": "select", "name": "dept",    "label": "Department", "options": ["Sales", "Support", "Accounting"]},
  {"type": "file",   "name": "doc",     "label": "Document",   "accept": ".pdf,.doc,.docx", "max_size_mb": 5},
  {"type": "textarea","name": "message","label": "Message",    "required": true}
]

The vendor:feedback.form component renders the form from the schema without requiring template changes when fields are added.

Submission Handling

class SubmissionHandler
{
    public function handle(int $formId, array $postData, array $files): HandleResult
    {
        $form = FormTable::getById($formId)->fetch();

        // Validate against the field schema
        $validator = new FormValidator($form['FIELDS_SCHEMA']);
        if (!$validator->validate($postData)) {
            return HandleResult::validationError($validator->getErrors());
        }

        // Anti-spam check
        if (!$this->spamChecker->check($postData, $form['SPAM_PROTECTION'])) {
            return HandleResult::spam();
        }

        // Save the submission
        $submissionId = SubmissionTable::add([
            'FORM_ID'    => $formId,
            'DATA'       => $postData,
            'IP'         => $_SERVER['REMOTE_ADDR'],
            'PAGE_URL'   => $_SERVER['HTTP_REFERER'] ?? '',
            'UTM_SOURCE' => $_COOKIE['utm_source'] ?? '',
            // ...
        ])->getId();

        // Upload files
        foreach ($files as $fieldName => $file) {
            $fileId = \CFile::SaveFile(\CFile::MakeFileArray($file['tmp_name']), 'feedback');
            AttachmentTable::add(['SUBMISSION_ID' => $submissionId, 'FILE_ID' => $fileId]);
        }

        // Execute actions (email, CRM, webhook)
        $this->dispatchActions($form['SUBMIT_ACTION'], $submissionId, $postData);

        return HandleResult::success();
    }
}

Routing and Actions

The submit_action field defines what happens after form submission:

{
  "email": {"to": ["[email protected]"], "template": "feedback_sales"},
  "crm": {"type": "lead", "responsible_id": 42, "fields_map": {"name": "TITLE", "phone": "PHONE"}},
  "webhook": {"url": "https://n8n.company.com/webhook/feedback", "method": "POST"}
}

Multiple actions execute sequentially. If one action fails (e.g., CRM is unavailable), the rest continue and the error is logged.

Anti-Spam

Three levels of protection:

  1. Honeypot — a hidden field in the form, automatically filled by bots
  2. Timing check — the form cannot be submitted faster than 3 seconds after loading (JavaScript + server-side)
  3. Rate limiting — no more than 3 submissions per IP per hour: checked against b_vendor_feedback_submission

reCAPTCHA v3 is connected as an optional module.

Analytics and Conversion

The form view counter is incremented via AJAX (a 1-pixel request when the form enters the viewport). Conversion = submissions / views:

In the admin dashboard:

  • Form funnel: views → started filling → submitted → marked as spam
  • UTM breakdown: which sources bring high-conversion submissions
  • Average form fill time
  • Hourly heat map: when submissions peak

Development Timeline

Stage Duration
ORM tables, form schema builder 1 day
Form rendering from schema, validation 1 day
Submission handler, file uploads 1 day
Email, CRM, Webhook actions 2 days
Anti-spam (honeypot, rate limit) 1 day
View counter, statistics 1 day
Admin interface, submission viewer 2 days
Testing 1 day

Total: 10 working days. Integration with a specific CRM (Bitrix24, amoCRM, RetailCRM) is estimated during the scoping stage.