Setting up ROI analytics for Bitrix24 advertising channels

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

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.