Setting Up ROI Analytics for Bitrix24 Advertising Channels
The built-in Bitrix24 CRM analytics shows the deal funnel and lead sources, but does not show how much was spent on each channel relative to revenue. ROI analytics is a computed metric that requires data from two sources: spend from advertising platforms and revenue from the CRM. A complete setup involves data collection, attribution mapping, and visualisation.
Attribution models
Before configuring reports, you need to decide on an attribution model — which touchpoint receives credit for the conversion.
First-click — the first channel through which the user arrived at the site. Good for identifying what attracts new audiences.
Last-click — the last channel before conversion. The default in GA4 and Metrica. Overvalues retargeting and branded queries.
Linear — equal distribution across all touchpoints. Requires storing the full touchpoint chain.
For most B2B companies with a long deal cycle (a month or more), the optimal approach is first-click + last-click — running two reports simultaneously. For e-commerce, last-click is sufficient.
Storing the touchpoint chain
For multi-touch attribution, a table of visit events linked to leads/deals is required:
class TouchpointTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'local_crm_touchpoints'; }
public static function getMap(): array
{
return [
new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new \Bitrix\Main\ORM\Fields\StringField('SESSION_ID'),
new \Bitrix\Main\ORM\Fields\IntegerField('LEAD_ID'),
new \Bitrix\Main\ORM\Fields\IntegerField('DEAL_ID'),
new \Bitrix\Main\ORM\Fields\StringField('UTM_SOURCE'),
new \Bitrix\Main\ORM\Fields\StringField('UTM_CAMPAIGN'),
new \Bitrix\Main\ORM\Fields\StringField('UTM_MEDIUM'),
new \Bitrix\Main\ORM\Fields\StringField('UTM_TERM'),
new \Bitrix\Main\ORM\Fields\IntegerField('TOUCH_ORDER'), // 1=first, N=last
new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
];
}
}
Touchpoint data is collected via JavaScript on the site: each visit with UTM parameters writes to a cookie/localStorage; on form submission, the full chain is sent to the server.
Calculating ROI
class RoiReportBuilder
{
public function buildReport(string $dateFrom, string $dateTo, string $attributionModel = 'last'): array
{
$deals = $this->getWonDeals($dateFrom, $dateTo);
$costs = $this->getAdCosts($dateFrom, $dateTo);
$revenueByChannel = [];
foreach ($deals as $deal) {
$channel = $this->getChannel($deal, $attributionModel);
$revenueByChannel[$channel] = ($revenueByChannel[$channel] ?? 0) + $deal['OPPORTUNITY'];
}
$result = [];
foreach ($costs as $channel => $cost) {
$revenue = $revenueByChannel[$channel] ?? 0;
$result[] = [
'channel' => $channel,
'spend' => $cost,
'revenue' => $revenue,
'profit' => $revenue - $cost,
'roi' => $cost > 0 ? round(($revenue - $cost) / $cost * 100, 1) : null,
'roas' => $cost > 0 ? round($revenue / $cost, 2) : null,
'cpl' => $cost > 0 ? round($cost / max(1, $this->getLeadsCount($channel, $dateFrom, $dateTo)), 0) : null,
];
}
usort($result, fn($a, $b) => ($b['roi'] ?? -PHP_INT_MAX) <=> ($a['roi'] ?? -PHP_INT_MAX));
return $result;
}
}
ROAS (Return on Ad Spend) and CPL (Cost Per Lead) complement ROI — ROAS shows how much revenue each unit of ad spend generated; CPL shows the cost per lead.
Dashboard in Bitrix24
Two options for displaying ROI analytics in Bitrix24.
Option 1: Custom report in /local/php_interface/admin/ — a table with a period filter, the ability to switch attribution models, and Excel export.
Option 2: Embedded Bitrix24 application (React) — a dashboard displayed on a dedicated portal page. Data comes from a custom backend (not directly from Bitrix24). Charts via Recharts or ApexCharts.
// React ROI dashboard component
function RoiDashboard() {
const [period, setPeriod] = useState({ from: startOfMonth, to: today });
const [model, setModel] = useState<'first' | 'last' | 'linear'>('last');
const { data, isLoading } = useQuery({
queryKey: ['roi', period, model],
queryFn: () => fetchRoiReport(period, model),
});
return (
<div>
<PeriodSelector value={period} onChange={setPeriod} />
<ModelSelector value={model} onChange={setModel} />
{isLoading ? <Spinner /> : (
<>
<RoiTable data={data?.channels} />
<SpendVsRevenueChart data={data?.channels} />
</>
)}
</div>
);
}
Key reports in the system
Channel summary table (main report):
| Channel | Spend | Leads | CPL | Revenue | ROAS | ROI |
|---|---|---|---|---|---|---|
| Yandex/brand | 45,000 | 38 | 1,184 | 380,000 | 8.4 | 744% |
| VK/retargeting | 28,000 | 22 | 1,273 | 115,000 | 4.1 | 311% |
| Direct/competitors | 67,000 | 19 | 3,526 | 95,000 | 1.4 | 42% |
Monthly trend — ROI trend per channel over time. Reveals seasonality and channel degradation.
Funnel by source — lead → qualified → deal conversion rate broken down by channel. A channel with cheap leads but low deal conversion may underperform a more expensive channel that generates high-quality leads.
Scope of work
- Defining the attribution model for the business logic
- Custom fields in leads and deals for UTM data
- Touchpoint chain collection (JavaScript + server)
- Ad spend import from advertising platforms (cron)
- Report with ROI, ROAS, CPL calculations
- Dashboard: admin section or Bitrix24 React application
Timeline: basic ROI report (last-click, single channel) — 1 week. Multi-channel dashboard with multiple attribution models — 3–5 weeks.







