Setting up ad network pixels on 1C-Bitrix

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
    1189
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    813
  • 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
    657
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Setting Up Advertising Network Pixels on 1C-Bitrix

VKontakte pixel, Facebook/Meta pixel, TikTok pixel, Yandex.Metrica counter — each requires code installation on your site and sending events about user actions. The task isn't just inserting <script> into template — that's simple. The task is sending correct events with correct data: product view, add to cart, checkout, purchase.

Architecture: GTM or Direct Installation

Two approaches:

Via GTM — all pixels are installed in one GTM container, site sends data via dataLayer. Plus: marketer manages pixels without developer. Minus: extra GTM request, GTM can be blocked by ad blockers.

Direct installation — pixel code is embedded directly in Bitrix template. Plus: faster, more reliable. Minus: each change requires deployment.

In practice: GTM for main pixels, direct installation for critical conversion counters.

VKontakte Pixel

VKontakte pixel code in Bitrix template (header.php):

<?php
$vkPixelId = \Bitrix\Main\Config\Option::get('custom', 'vk_pixel_id', '');
?>
<?php if ($vkPixelId): ?>
<script>
!function(){var t=document.createElement("script");t.type="text/javascript",
t.async=!0,t.src='https://vk.com/js/api/openapi.js?169',
t.onload=function(){VK.Retargeting.Init("<?= htmlspecialchars($vkPixelId) ?>"),
VK.Retargeting.Hit()},document.head.appendChild(t)}();
</script>
<noscript><img src="https://vk.com/rtrg?p=<?= htmlspecialchars($vkPixelId) ?>"
style="position:fixed;left:-999px;" alt=""/></noscript>
<?php endif; ?>

Add to cart event for VKontakte:

// Call when adding to cart
if (typeof VK !== 'undefined') {
    VK.Retargeting.Event('add_to_cart');
    // Or with parameters for dynamic retargeting:
    VK.Retargeting.ProductEvent(productId, 'add_to_cart', {
        price: productPrice,
        currency: 'RUB'
    });
}

Facebook/Meta Pixel

<?php $fbPixelId = \Bitrix\Main\Config\Option::get('custom', 'fb_pixel_id', ''); ?>
<?php if ($fbPixelId): ?>
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '<?= htmlspecialchars($fbPixelId) ?>');
fbq('track', 'PageView');
</script>
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=<?= htmlspecialchars($fbPixelId) ?>&ev=PageView&noscript=1"/></noscript>
<?php endif; ?>

ViewContent event on product page — in component template:

// result_modifier.php of catalog.element component
$this->arResult['FB_CONTENT'] = json_encode([
    'content_ids' => [$arResult['ID']],
    'content_type' => 'product',
    'value' => (float)($arResult['CATALOG_PRICE']['BASE']['PRICE'] ?? 0),
    'currency' => 'RUB'
], JSON_UNESCAPED_UNICODE);
// In template.php
fbq('track', 'ViewContent', <?= $arResult['FB_CONTENT'] ?>);

Yandex.Metrica Counter with Goals

<?php $yandexMetrikaId = \Bitrix\Main\Config\Option::get('custom', 'ym_counter_id', ''); ?>
<?php if ($yandexMetrikaId): ?>
<script type="text/javascript">
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
var z = m[i],d=e.createElement(t),n=e.getElementsByTagName(t)[0],b=e.location;
z.l=1*new Date();d.async=1;d.src=r+'?'+Math.random();
k=function(){n.parentNode.insertBefore(d,n)};
if(e.readyState=='loading'){e.addEventListener('onreadystatechange',k)}else{k()}}
(window, document, 'script', 'https://mc.yandex.ru/metrika/tag.js', 'ym'));
ym(<?= (int)$yandexMetrikaId ?>, 'init', {
    clickmap:true,
    trackLinks:true,
    accurateTrackBounce:true,
    webvisor:true,
    ecommerce:"dataLayer"
});
</script>
<?php endif; ?>

Purchase Event for All Pixels

On "Thank You" page — unified block for all pixels:

<?php
$orderId = (int)($_SESSION['SALE_ORDER_ID_REDIRECTED'] ?? 0);
if ($orderId > 0):
    $order = \Bitrix\Sale\Order::load($orderId);
    $orderPrice = $order ? (float)$order->getPrice() : 0;
    $orderCurrency = $order ? $order->getCurrency() : 'RUB';
?>
<script>
(function() {
    var orderId = '<?= $orderId ?>',
        orderPrice = <?= $orderPrice ?>,
        currency = '<?= htmlspecialchars($orderCurrency) ?>';

    // VKontakte
    if (typeof VK !== 'undefined') {
        VK.Retargeting.Event('purchase');
    }

    // Facebook
    if (typeof fbq !== 'undefined') {
        fbq('track', 'Purchase', {
            value: orderPrice,
            currency: currency,
            order_id: orderId
        });
    }

    // Yandex.Metrica — goal
    if (typeof ym !== 'undefined') {
        ym(<?= (int)\Bitrix\Main\Config\Option::get('custom', 'ym_counter_id') ?>,
           'reachGoal', 'purchase', {
            order_price: orderPrice,
            currency: currency
        });
    }
})();
</script>
<?php endif; ?>

Consent Mode and User Consent

European GDPR and Russian Federal Law 152-FZ require user consent for data transmission to pixels. Google Consent Mode v2 and analogues allow deferring pixel activation until consent is obtained.

Basic implementation:

// Set before GTM loads
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}

// By default — deny
gtag('consent', 'default', {
    'ad_storage': 'denied',
    'analytics_storage': 'denied',
    'wait_for_update': 500
});

After user consent (via cookie banner):

gtag('consent', 'update', {
    'ad_storage': 'granted',
    'analytics_storage': 'granted'
});

Save user choice in localStorage and restore on subsequent pages.