Development of Calculators on a 1C-Bitrix Website
A calculator on a website is one of the few interactive elements that directly affects conversion. The user enters parameters, sees the total price or result, and makes a decision right there without leaving for email or a messenger. The typical problem: standard 1C-Bitrix forms cannot calculate in real time, and off-the-shelf plugins do not cover business-specific logic.
Approaches to implementing calculators on Bitrix
On 1C-Bitrix, calculators are implemented in three ways, each with its own area of application:
1. Component with AJAX calls to PHP logic
The classic approach for complex calculations where the logic must stay on the server (current prices from the database, discounts, integration with 1C). The component lives in bitrix/components/vendor/calculator/, and the template sends AJAX to $APPLICATION->IncludeComponent or to a dedicated ajax.php.
2. JavaScript calculator with server-side validation
Calculation directly in the browser for instant response, with final validation on the server when the form is submitted. Suitable for most price calculators where the data is static (rates, coefficients).
3. Bitrix Form Builder + custom JS
A quick option for simple cases: a standard Bitrix form with an added JavaScript handler. Does not scale, but can be launched in 1 day.
Calculator component architecture
Structure of a custom component:
/bitrix/components/custom/calculator/
component.php # Main component logic
.parameters.php # Parameters for admin panel configuration
templates/
.default/
template.php # HTML template
script.js # JS calculation logic
style.css
The component.php file is the heart of the component. This is where the calculator data is loaded:
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
class CustomCalculatorComponent extends CBitrixComponent
{
public function executeComponent()
{
// Load rates from an info block
$arFilter = [
'IBLOCK_ID' => $this->arParams['RATES_IBLOCK_ID'],
'ACTIVE' => 'Y',
];
$rsRates = CIBlockElement::GetList(
['SORT' => 'ASC'],
$arFilter,
false,
false,
['ID', 'NAME', 'PROPERTY_*']
);
$this->arResult['RATES'] = [];
while ($arRate = $rsRates->GetNext()) {
$this->arResult['RATES'][] = $arRate;
}
// Pass data to the template via JSON for JS
$this->arResult['RATES_JSON'] = json_encode(
$this->arResult['RATES'],
JSON_UNESCAPED_UNICODE
);
$this->includeComponentTemplate();
}
}
In the template, data is passed to JavaScript:
// template.php
<script>
const CALCULATOR_DATA = <?= $arResult['RATES_JSON'] ?>;
</script>
AJAX handling for server-side calculations
If the calculation cannot be done on the client (dynamic prices, stock availability check), use AJAX:
// ajax.php in the component folder
define('STOP_STATISTICS', true);
define('NO_KEEP_STATISTIC', 'Y');
define('DisableEventsCheck', true);
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');
if (!check_bitrix_sessid()) {
echo json_encode(['error' => 'Invalid session']);
die();
}
$action = $_POST['action'] ?? '';
if ($action === 'calculate') {
$params = json_decode(file_get_contents('php://input'), true);
// Calculation logic
$result = calculatePrice($params);
header('Content-Type: application/json');
echo json_encode(['success' => true, 'data' => $result]);
}
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php');
Call from JavaScript:
async function calculate(params) {
const response = await fetch('/bitrix/components/custom/calculator/ajax.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'calculate',
sessid: BX.bitrix_sessid(), // Bitrix CSRF token
...params
})
});
return response.json();
}
Saving a request from the calculator
The calculation result usually needs to be attached to a request. Options:
-
Standard feedback form (
bitrix:form.result.new) — calculator results are passed via hidden fields -
Creating a lead/deal in CRM — via
CCrmLead::Add()or the REST API if it needs to go directly into the funnel - Writing to an info block — for storing calculation history
// Creating a lead with calculator data
use Bitrix\Crm;
$leadData = [
'TITLE' => 'Calculator request: ' . $calcTitle,
'NAME' => $arFields['name'],
'PHONE' => [['VALUE' => $arFields['phone'], 'VALUE_TYPE' => 'WORK']],
'COMMENTS' => 'Calculation parameters: ' . json_encode($calcParams),
'UF_CRM_CALC_RESULT' => $calcResult,
];
$leadId = CCrmLead::Add($leadData, true, ['REGISTER_SONET_EVENT' => false]);
Caching calculator data
If the calculator fetches data from info blocks or external sources, caching is important:
$cacheTime = 3600; // 1 hour
$cache = Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache($cacheTime, 'calculator_rates_' . $iblockId, '/calculator/')) {
$arRates = $cache->getVars();
} elseif ($cache->startDataCache()) {
$arRates = loadRatesFromIblock($iblockId);
$cache->endDataCache($arRates);
}
Development timelines
| Calculator type | Complexity | Timeline |
|---|---|---|
| Simple (2–5 fields, JS) | S | 2–4 days |
| Medium (6–15 fields, conditional logic) | M | 1–2 weeks |
| Complex (dynamic data, 1C integration) | L | 3–5 weeks |
| Multi-step with CRM save | XL | 4–8 weeks |
The most time-consuming part is not the calculation logic itself, but formalizing the business rules: clients often lack a ready specification, and working it out takes as long as the actual development.







