Setting Up a Delivery Calculator on a 1C-Bitrix Website
A delivery calculator is a widget on the product page or in the shopping cart that allows the customer to enter an address or postal code and get the shipping cost before placing an order. It reduces cart abandonment: the customer knows the delivery price upfront and does not abandon the cart at checkout.
Where to place the calculator
Product page — shows the cost immediately when browsing. Suitable for large or expensive items where delivery significantly affects the purchase decision.
Shopping cart — the standard location. The customer sees the total with delivery before clicking "Checkout."
Landing page / promotional page — for promotions with free delivery from a certain amount: display "Add items worth X to get free delivery."
Implementation on the 1C-Bitrix side
The calculator works via AJAX. On the frontend — a city/postal code input field and a button. On the backend — a 1C-Bitrix component that calls the delivery service calculation method without creating an order.
// /local/components/delivery_calculator/class.php
class DeliveryCalculatorComponent extends \CBitrixComponent
{
public function executeComponent(): void
{
if ($this->request->isAjaxRequest()) {
$this->ajaxAction();
return;
}
$this->includeComponentTemplate();
}
private function ajaxAction(): void
{
$city = $this->request->getPost('city');
$weight = (int)$this->request->getPost('weight');
$amount = (float)$this->request->getPost('amount');
$results = [];
$services = $this->getActiveDeliveryServices();
foreach ($services as $service) {
$price = $this->calcServicePrice($service, $city, $weight, $amount);
if ($price !== null) {
$results[] = [
'name' => $service->getName(),
'price' => $price,
'period' => $service->getPeriodText(),
];
}
}
\Bitrix\Main\Application::getInstance()->getContext()
->getResponse()->setContentType('application/json');
echo json_encode(['items' => $results]);
die();
}
}
Standard 1C-Bitrix calculation mechanism
Calling cost calculation for a specific service without a real order:
private function calcServicePrice(
\Bitrix\Sale\Delivery\Services\Base $service,
string $city,
int $weight,
float $amount
): ?float {
// Create a temporary shipment object for calculation
$fakePropValues = ['CITY' => $city];
$calcResult = $service->calculate(
new \Bitrix\Sale\Delivery\CalculationResult(),
$fakePropValues,
$weight,
$amount
);
if ($calcResult->isSuccess()) {
return $calcResult->getPrice();
}
return null;
}
For a more accurate calculation, create a temporary \Bitrix\Sale\Shipment object via a stub order — this allows the full calculateConcrete() method of each service to be used.
Caching results
Cost calculations are API requests to external services. Cache for 15–30 minutes:
$cacheKey = 'delivery_calc_' . md5($city . $weight . $amount);
$cached = \Bitrix\Main\Data\Cache::createInstance();
if ($cached->startDataCache(1800, $cacheKey, '/delivery_calc')) {
$results = $this->fetchPrices($city, $weight, $amount);
$cached->endDataCache(['results' => $results]);
}
$results = $cached->getVars()['results'];
Without caching, every city entry in the field triggers a request to the CDEK or Boxberry API — causing both interface delays and quota consumption.
City autocomplete
For convenience, add autocomplete with city suggestions. The suggestion source is either a custom list of major cities in JSON, or a geocoding API (Yandex Geocoder, DaData).
const cityInput = document.getElementById('delivery_city');
cityInput.addEventListener('input', debounce(function() {
fetch('/bitrix/services/main/ajax.php?action=delivery_city_suggest', {
method: 'POST',
body: new FormData(this.closest('form')),
})
.then(r => r.json())
.then(data => showSuggestions(data.cities));
}, 300));
The debounce function with a 300 ms delay prevents requests on every keystroke — only after a pause in typing.
Updating cart total without page reload
When using the calculator in the cart, the total must update dynamically. In 1C-Bitrix this is implemented via the ajax_reload mechanism in the bitrix:sale.basket.basket component parameters, or through custom AJAX logic:
function recalcDelivery(city) {
fetch('/bitrix/services/main/ajax.php', {
method: 'POST',
body: JSON.stringify({ action: 'calc_delivery', city, weight: cartWeight }),
headers: { 'Content-Type': 'application/json' },
})
.then(r => r.json())
.then(data => {
document.getElementById('delivery-price').textContent = data.price + ' ₽';
document.getElementById('total-price').textContent = (cartAmount + data.price) + ' ₽';
});
}
Displaying multiple delivery options
The cart calculator shows all available options at once: "CDEK — 350 ₽, 3 days", "Russian Post — 180 ₽, 7 days", "Pickup — 0 ₽." The customer selects the preferred option — the total updates. The selected method is passed to the next checkout step via the hidden field DELIVERY_ID.
Implementation timelines
Setting up a delivery calculator with AJAX requests and caching — 2–3 working days. With city autocomplete, dynamic cart total update, and integration of multiple services — 3–4 days.







