1C-Bitrix Integration with Callibri
Callibri is a call tracking and multi-channel analytics platform. Unlike basic Google Analytics, it can stitch a call to a specific traffic source and pass UTM parameters to the CRM. The problem with standard setups: the Callibri script collects data in its own system, while leads from Bitrix forms live in b_form_result, with no connection between them. The manager sees a call but does not know which ad brought the customer. The integration goal is to close the chain: source → action → lead/call → deal in CRM.
Integration Architecture
Callibri provides two mechanisms: a JavaScript API for the client side and a REST API for server-side interaction. A complete Bitrix integration requires both.
Data flow diagram:
Visitor → Callibri JS replaces the number
→ Call is recorded in Callibri
→ Webhook from Callibri (POST to your endpoint)
→ Bitrix handler
→ Create lead/deal in Bitrix CRM
→ Attach UTM parameters to the deal
In parallel, for online forms:
Bitrix form submission
→ JS handler: reads callibri_visitor_uid from cookie
→ Passes uid along with form data
→ Server handler saves uid to lead properties
→ Callibri REST API: request visit details by uid
Configuring the Callibri Webhook
In the Callibri account: Settings → Integrations → Webhook. Enter your handler URL. Callibri sends a POST with a JSON payload on every call, chat, or lead.
Payload structure (key fields):
{
"call_id": "98765432",
"call_type": "call",
"caller_number": "+79161234567",
"call_date": "2024-03-15 14:23:11",
"utm_source": "yandex",
"utm_medium": "cpc",
"utm_campaign": "brand_kw",
"duration": 145,
"is_target": true,
"visitor_id": "callibri_abc123"
}
The handler in Bitrix — a dedicated component or /local/api/callibri-webhook.php:
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');
$rawInput = file_get_contents('php://input');
$data = json_decode($rawInput, true);
if (empty($data) || empty($data['caller_number'])) {
http_response_code(400);
exit;
}
// Verification via a secret token in the header
$token = $_SERVER['HTTP_X_CALLIBRI_TOKEN'] ?? '';
if ($token !== \Bitrix\Main\Config\Option::get('local.callibri', 'webhook_secret')) {
http_response_code(403);
exit;
}
(new \Local\Callibri\LeadCreator())->createFromWebhook($data);
http_response_code(200);
echo json_encode(['status' => 'ok']);
Creating a Lead in CRM from a Call
namespace Local\Callibri;
use Bitrix\Crm\LeadTable;
use Bitrix\Main\Type\DateTime;
class LeadCreator
{
public function createFromWebhook(array $data): int
{
$fields = [
'TITLE' => 'Callibri call: ' . $data['caller_number'],
'PHONE' => [['VALUE' => $data['caller_number'], 'VALUE_TYPE' => 'WORK']],
'SOURCE_ID' => 'CALL',
'STATUS_ID' => 'NEW',
'ASSIGNED_BY_ID' => $this->resolveAssignee($data),
'UF_CALLIBRI_ID' => $data['call_id'],
'UF_UTM_SOURCE' => $data['utm_source'] ?? '',
'UF_UTM_MEDIUM' => $data['utm_medium'] ?? '',
'UF_UTM_CAMPAIGN'=> $data['utm_campaign'] ?? '',
'UF_CALL_DURATION' => (int)($data['duration'] ?? 0),
'COMMENTS' => $this->buildComment($data),
];
$lead = new \CCrmLead(false);
$leadId = $lead->Add($fields, true, ['DISABLE_USER_FIELD_CHECK' => false]);
if (!$leadId) {
\CEventLog::Add([
'SEVERITY' => 'ERROR',
'AUDIT_TYPE_ID' => 'CALLIBRI_LEAD_FAIL',
'MODULE_ID' => 'local.callibri',
'DESCRIPTION' => $lead->LAST_ERROR,
]);
}
return (int)$leadId;
}
private function buildComment(array $data): string
{
$isTarget = $data['is_target'] ? 'Targeted' : 'Non-targeted';
return sprintf(
"Callibri ID: %s\nType: %s\nDuration: %d sec.\nSource: %s / %s / %s",
$data['call_id'],
$isTarget,
$data['duration'] ?? 0,
$data['utm_source'] ?? '—',
$data['utm_medium'] ?? '—',
$data['utm_campaign'] ?? '—'
);
}
}
Linking a Visit to a Bitrix Form
Callibri sets a callibri_visitor_uid cookie on the client side. Intercept the form submission and inject the uid as a hidden field.
JavaScript on the page with the form:
document.addEventListener('DOMContentLoaded', function () {
const forms = document.querySelectorAll('form.bx-form, form[data-bitrix-form]');
forms.forEach(function (form) {
const uid = getCookie('callibri_visitor_uid');
if (uid) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'callibri_uid';
input.value = uid;
form.appendChild(input);
}
});
});
function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? match[2] : null;
}
On the server in the form handler (OnBeforeIBlockElementAdd or a custom handler):
$callibriUid = htmlspecialchars($_POST['callibri_uid'] ?? '');
if ($callibriUid) {
// Save to the custom lead field
$leadFields['UF_CALLIBRI_UID'] = $callibriUid;
// Request visit details from the Callibri API
$visitData = (new \Local\Callibri\ApiClient())->getVisitByUid($callibriUid);
if ($visitData) {
$leadFields['UF_UTM_SOURCE'] = $visitData['utm_source'] ?? '';
$leadFields['UF_UTM_CAMPAIGN'] = $visitData['utm_campaign'] ?? '';
}
}
Lead Deduplication
A common problem: a customer called and then submitted a form. Two separate leads for the same contact.
public function findExistingLead(string $phone): ?int
{
$phone = preg_replace('/\D/', '', $phone);
$result = \CCrmLead::GetList(
['DATE_CREATE' => 'DESC'],
[
'PHONE' => $phone,
'STATUS_ID' => 'NEW',
'>DATE_CREATE' => (new DateTime())->add('-1D')->format('d.m.Y H:i:s'),
],
false, ['nTopCount' => 1],
['ID', 'UF_CALLIBRI_ID']
);
if ($row = $result->Fetch()) {
return (int)$row['ID'];
}
return null;
}
If a recent lead is found — update it with the new data rather than creating a new one.
Custom Fields for UTM in CRM
Fields are created via CUserTypeEntity or through the CRM administration interface. Recommended set:
| Field code | Type | Purpose |
|---|---|---|
| UF_CALLIBRI_ID | string | Call/chat ID in Callibri |
| UF_CALLIBRI_UID | string | Visitor UID for form stitching |
| UF_UTM_SOURCE | string | utm_source |
| UF_UTM_MEDIUM | string | utm_medium |
| UF_UTM_CAMPAIGN | string | utm_campaign |
| UF_UTM_TERM | string | utm_term |
| UF_CALL_DURATION | integer | Call duration, seconds |
| UF_IS_TARGET_CALL | boolean | Targeted call flag |
Scope of Work
- Register the
local.callibricomponent and set module options - Develop the webhook handler with token verification
- Create custom fields in CRM (lead, deal)
- Callibri REST API client (fetching visit details)
- JS form-interception script for passing visitor_uid
- Lead deduplication logic by phone number
- End-to-end scenario testing: call → lead with UTM
Timelines: basic integration (webhook → lead) — 1–2 weeks. Full stitching with forms, deduplication, and UTM display on the deal card — 3–4 weeks.







