Configuration of Phone Number Substitution by Traffic Sources in 1C-Bitrix
A marketer wants to know how many calls come from Yandex.Direct vs. organic. If the site has one phone number, this is impossible without call tracking. Phone number substitution (dynamic number insertion) — replacing the displayed number depending on the traffic source.
bitrix.seo Module and UTM Parameters
Bitrix does not have built-in call tracking. Integration is implemented in two ways: through external services (CoMagic, Calltouch, Roistat) with their JavaScript code, or through your own implementation based on sessions and UTM parameters.
For your own implementation, the traffic source is read from $_GET on first visit and saved to the session. Parameter set: utm_source, utm_medium, utm_campaign for paid traffic; gclid for Google Ads; yclid for Yandex.Direct; fbclid for Facebook.
Handler to save traffic source to session:
AddEventHandler('main', 'OnPageStart', function() {
if (isset($_GET['utm_source']) || isset($_GET['yclid']) || isset($_GET['gclid'])) {
$_SESSION['traffic_source'] = [
'utm_source' => $_GET['utm_source'] ?? '',
'utm_medium' => $_GET['utm_medium'] ?? '',
'utm_campaign' => $_GET['utm_campaign'] ?? '',
'yclid' => $_GET['yclid'] ?? '',
'gclid' => $_GET['gclid'] ?? '',
'referrer' => $_SERVER['HTTP_REFERER'] ?? '',
'timestamp' => time(),
];
}
if (!isset($_SESSION['traffic_source'])) {
$_SESSION['traffic_source'] = [
'referrer' => $_SERVER['HTTP_REFERER'] ?? '',
'direct' => true,
];
}
});
Traffic Source to Phone Number Mapping
For each traffic source, a separate phone number is assigned. The mapping is stored in a custom table or in component settings. Table structure:
CREATE TABLE custom_calltracking_numbers (
id SERIAL PRIMARY KEY,
source_key VARCHAR(100) NOT NULL, -- 'yclid', 'gclid', 'utm_source:yandex', ...
phone VARCHAR(30) NOT NULL,
description VARCHAR(255),
active BOOLEAN DEFAULT true
);
Logic for selecting a phone number:
function getPhoneByTrafficSource(array $source): string {
$default = '+375 (17) 000-00-00';
if (!empty($source['yclid'])) {
return getPhoneFromDb('yclid');
}
if (!empty($source['gclid'])) {
return getPhoneFromDb('gclid');
}
if (!empty($source['utm_source'])) {
return getPhoneFromDb('utm_source:' . $source['utm_source']) ?: $default;
}
if (!empty($source['referrer'])) {
$host = parse_url($source['referrer'], PHP_URL_HOST);
return getPhoneFromDb('referrer:' . $host) ?: $default;
}
return $default;
}
Phone Number Substitution in Site Template
The phone number in the template (/bitrix/templates/[template]/header.php) is replaced with a function call instead of hardcode:
$phone = getPhoneByTrafficSource($_SESSION['traffic_source'] ?? []);
echo '<a href="tel:' . preg_replace('/\D/', '', $phone) . '">' . $phone . '</a>';
To substitute phone numbers in already formatted HTML (if the template is not under your control) — use the OnEndBufferContent event handler:
AddEventHandler('main', 'OnEndBufferContent', function(&$content) {
$phone = getPhoneByTrafficSource($_SESSION['traffic_source'] ?? []);
$content = str_replace('+375 (17) 000-00-00', $phone, $content);
});
Passing Traffic Source to Order
When placing an order, the traffic source is passed to order properties or the COMMENTS field. This allows you to see in CRM where each purchase came from.
AddEventHandler('sale', 'OnSaleOrderBeforeSaved', function(\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
$source = $_SESSION['traffic_source'] ?? [];
$comment = $order->getField('USER_DESCRIPTION');
$sourceStr = json_encode($source, JSON_UNESCAPED_UNICODE);
$order->setField('MANAGER_NOTES', 'Source: ' . $sourceStr);
});
Call Statistics
For complete analysis, it's necessary to record not just phone number display, but actual calls. External call tracking services provide a webhook on incoming call — it can be processed and recorded in a custom table with binding to USER_ID if the user is authorized, or to a session identifier.







