1C-Bitrix Integration with Yandex.Maps

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

1C-Bitrix Integration with Yandex Maps

The contacts page shows a static map image instead of an interactive one. The delivery section provides no way to select a zone. Managers cannot see orders on a map by district. Yandex Maps API v3 covers all of these use cases, but integration requires careful handling of API keys and server-side geofencing logic.

Yandex Maps API: versions and keys

The current version is JavaScript API 3.0 (jsapi v3). Version 2.1 is deprecated and Yandex will discontinue support. An API key is required from the Yandex Developer Console (developer.tech.yandex.ru). The key is bound to a domain. Store it in COption::GetOptionString('site', 'ymaps_api_key').

Basic map initialization

<!-- In the component template -->
<div id="ymap-container" style="width:100%;height:400px"></div>

<script src="https://api-maps.yandex.ru/v3/?apikey=<?= COption::GetOptionString('site', 'ymaps_api_key') ?>&lang=ru_RU"></script>
<script>
ymaps3.ready.then(() => {
    const {YMap, YMapDefaultSchemeLayer, YMapMarker, YMapDefaultFeaturesLayer} = ymaps3;

    const map = new YMap(document.getElementById('ymap-container'), {
        location: { center: [37.617644, 55.755819], zoom: 10 }
    });
    map.addChild(new YMapDefaultSchemeLayer());
    map.addChild(new YMapDefaultFeaturesLayer());

    // Marker from infoblock settings
    const marker = new YMapMarker({coordinates: [<?= $lon ?>, <?= $lat ?>]});
    map.addChild(marker);
});
</script>

Office/store coordinates are stored in infoblock element properties (type N for latitude and longitude) or in a custom property of type MAP.

Address geocoding

When importing addresses or adding a new object (office, pickup point), retrieve coordinates via the Geocoder API:

function geocodeAddress(string $address): ?array {
    $apiKey = COption::GetOptionString('site', 'ymaps_api_key');
    $url = 'https://geocode-maps.yandex.ru/1.x/?apikey=' . $apiKey
         . '&geocode=' . urlencode($address) . '&format=json&results=1';

    $http = new \Bitrix\Main\Web\HttpClient();
    $response = json_decode($http->get($url), true);

    $pos = $response['response']['GeoObjectCollection']
                    ['featureMember'][0]['GeoObject']
                    ['Point']['pos'] ?? null;
    if (!$pos) return null;

    [$lon, $lat] = explode(' ', $pos);
    return ['lat' => (float)$lat, 'lon' => (float)$lon];
}

Cache the result — re-geocoding the same address is unnecessary. Cache in b_cached_files via CPHPCache or in a dedicated table.

Delivery zones

The task: when placing an order, the user clicks on the map or enters an address — the system determines the delivery zone and cost.

Step 1. Draw delivery zones as polygons and store them in an infoblock as a JSON string of vertex coordinates.

Step 2. Server-side check: determine whether a point lies inside a polygon (Ray Casting algorithm). PHP implementation:

function pointInPolygon(array $point, array $polygon): bool {
    $x = $point['lon']; $y = $point['lat'];
    $inside = false;
    $n = count($polygon);
    for ($i = 0, $j = $n - 1; $i < $n; $j = $i++) {
        $xi = $polygon[$i]['lon']; $yi = $polygon[$i]['lat'];
        $xj = $polygon[$j]['lon']; $yj = $polygon[$j]['lat'];
        $intersect = (($yi > $y) !== ($yj > $y))
                   && ($x < ($xj - $xi) * ($y - $yi) / ($yj - $yi) + $xi);
        if ($intersect) $inside = !$inside;
    }
    return $inside;
}

Step 3. The Ajax handler in the checkout component receives the address, geocodes it, determines the zone, and returns the delivery cost. The cost is populated in the form before the order is placed.

Dealer/store map

A common task: a map with point clustering. Fetch all active elements with coordinates from the "Stores" infoblock and pass them to the frontend as JSON:

$stores = CIBlockElement::GetList(
    ['SORT' => 'ASC'],
    ['IBLOCK_ID' => STORES_IBLOCK_ID, 'ACTIVE' => 'Y'],
    false, false,
    ['ID', 'NAME', 'PROPERTY_LAT', 'PROPERTY_LON', 'PROPERTY_ADDRESS', 'PROPERTY_PHONE']
);
// Build a GeoJSON Feature Collection

On the frontend — YMapClusterer from the @yandex/ymaps3-clusterer package for automatic marker grouping when zooming out.

Task Effort
Basic map with markers 4–6 h
Geocoding + cache 3–4 h
Delivery zones (polygons + server-side check) 8–12 h
Store map with clustering 6–8 h