Setting up a shipping calculator on the 1C-Bitrix website

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

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.