Dynamic Number Insertion by Traffic Source in 1C-Bitrix
A marketer wants to know how many calls come from Yandex.Direct versus organic traffic. If your site has a single phone number, this is impossible without call tracking. Dynamic number insertion (DNI) – replacing the displayed number based on the traffic source – solves this. We have implemented dozens of such turnkey integrations – no external services, just pure PHP and Bitrix. Savings on external services can reach 40%.
How Dynamic Number Insertion Solves Call Attribution
Each time a visitor lands, the system identifies their source: UTM tags, click IDs (yclid, gclid), and referrer. If the source is identified, the corresponding phone number from a mapping table is displayed. Thus, you see that a call to +375 29 111-22-33 came from Yandex.Direct, while +375 29 444-55-66 came from organic. Data is recorded in the order and CRM. In practice, up to 80% of calls are correctly attributed after setup. With 2,000 calls per month, that is up to 1,600 attributed.
What You Need for Your Own Call Tracking Integration
Bitrix does not have built-in call tracking. There are two paths: external services (CoMagic, Calltouch, Roistat) with their JavaScript code and monthly fees, or your own implementation based on sessions and UTM parameters. We offer the second option – it is cheaper (only the cost of additional numbers) and fully controllable. Average savings are 60–80% compared to an external service subscription.
According to 1C-Bitrix documentation, the OnPageStart handler runs on every request.
Comparison of Approaches
| Criterion | External Service | In-house Implementation |
|---|---|---|
| Monthly fee | Recurring (per plan) | Only number rental |
| Data depth | Full (recording, duration) | Number display only |
| Bitrix24 integration | Via API | Directly via events |
| Launch speed | 1 day | 2-3 days |
| Dependency on third-party code | Yes | No |
In-house solution wins on cost and control. External services provide more analytics (call recording, precise attribution) but require budget.
Source Detection Priorities
The rule for selecting a number is based on priority: if yclid exists – number for Yandex.Direct, if gclid – for Google Ads, then UTM channel and referrer. This prevents conflicts.
| Priority | Source | Key in Table |
|---|---|---|
| 1 | yclid (Yandex.Direct) | yclid |
| 2 | gclid (Google Ads) | gclid |
| 3 | utm_source | utm_source:{value} |
| 4 | referrer | referrer:{domain} |
How We Do It: Stack and Code
To detect the traffic source on the first visit, we use the OnPageStart handler. Parameters are saved in the 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, ]; } }); Source-to-number mapping is stored in a separate table:
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 ); Number selection logic:
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; } Number substitution in the site template is done by replacing the hardcoded value with the function call:
$phone = getPhoneByTrafficSource($_SESSION['traffic_source'] ?? []); echo '<a href="tel:' . preg_replace('/\D/', '', $phone) . '">' . $phone . '</a>'; If the template is not editable, we use the OnEndBufferContent handler:
AddEventHandler('main', 'OnEndBufferContent', function(&$content) { $phone = getPhoneByTrafficSource($_SESSION['traffic_source'] ?? []); $content = str_replace('+375 (17) 000-00-00', $phone, $content); }); Work Process
- Analytics – determine which traffic sources are important, agree on list of numbers.
- Design – develop table schema and priority logic.
- Implementation – write handlers, create table, integrate into template.
- Testing – verify substitution for each source (UTM, clicks, referrals).
- Deployment – push to production, set up monitoring.
Case Study
Case: an electronics e‑commerce store with four numbers for different channels. After setup, the share of unassigned calls dropped from 70% to 15%. Analytics showed that 35% of calls came from organic, 40% from Yandex.Direct, and the rest from Google Ads and social media. Based on this data, the advertising budget was reallocated, increasing conversion by 12%.
What’s Included in the Work
- Setup of OnPageStart and OnEndBufferContent handlers
- Creation of the custom_calltracking_numbers table
- Implementation of the number selection function with priorities
- Number substitution in the template or via event
- Passing the traffic source to the order (USER_DESCRIPTION field)
- Documentation on adding new numbers
- 30‑day warranty for correct operation
Typical mistake: number caching
If you use tagged cache or full page caching, the number may be fixed for all visitors. Solution: disable caching for dynamic numbers or use OnEndBufferContent for replacement after cache.Timeline and Cost
Setup takes from 2 to 5 days – depending on the complexity of mapping and access to the admin panel. The cost is calculated individually after auditing your current site. We have been working with Bitrix for over 5 years, with more than 30 call‑tracking projects behind us. Contact us for an estimate of your project – we will prepare a proposal within one day. Get a consultation on your task and save up to 40% on call tracking.
Typical Mistakes in Self-Implementation
- Overriding the number for an already authenticated user – the session should be created only on the first visit.
- Ignoring caching – the number is cached in HTML; you need to clear component cache or use tagged cache.
- No default number – for direct visits and unsupported sources.
If you want to implement your own number substitution without monthly payments to external services, let us evaluate your project – just write to us.

