Setting up advertising cost linking with Bitrix24 CRM

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

Linking Ad Spend to Bitrix24 CRM

Ad spend lives in Yandex Direct, Google Ads, VKontakte, myTarget — each in its own dashboard with its own metrics. Revenue lives in Bitrix24 CRM. Without connecting the two, it is impossible to calculate real ROI by channel: how much was spent on Direct and how much of that closed into money. Setting up this link is a task at the intersection of advertising APIs and CRM.

Attribution principle

The connection "ad → lead → deal → revenue" is built on UTM tags. Each ad is tagged with UTM parameters that are captured in Bitrix24 when a lead is created. After a deal closes, the revenue from that deal is attributed to the campaign.

utm_source=yandex&utm_medium=cpc&utm_campaign=brand&utm_term=buy
  → Lead (UF_CRM_UTM_*) → Deal → Amount
    + Campaign spend from Yandex Direct API
    = ROI

Custom field structure

Deals in Bitrix24 need fields to store UTM data:

Field Code Type
Source UF_CRM_UTM_SOURCE string
Campaign UF_CRM_UTM_CAMPAIGN string
Campaign ID UF_CRM_CAMPAIGN_ID string
Medium UF_CRM_UTM_MEDIUM string
Keyword UF_CRM_UTM_TERM string
Ad ID UF_CRM_AD_ID string

Fields are created via crm.userfield.add or through the Bitrix24 interface.

When a lead is created from any advertising channel (Direct, VK, Facebook) — UTM tags are saved to these fields. When a lead is converted to a deal, the fields are copied (configured via "Sources" in Bitrix24 or via REST).

Importing ad spend from advertising platforms

A daily cron job imports the previous day's spend from each advertising platform into an aggregation table:

// Yandex Direct: campaign spend for the day
public function importDirectCosts(string $date): void
{
    $report = $this->directApi->getReport([
        'ReportType'    => 'CAMPAIGN_PERFORMANCE_REPORT',
        'DateRangeType' => 'CUSTOM_DATE',
        'DateFrom'      => $date,
        'DateTo'        => $date,
        'FieldNames'    => ['CampaignId', 'CampaignName', 'Cost', 'Clicks', 'Impressions'],
    ]);

    foreach ($report as $row) {
        AdCostTable::add([
            'DATE'        => $date,
            'SOURCE'      => 'yandex',
            'CAMPAIGN_ID' => $row['CampaignId'],
            'CAMPAIGN'    => $row['CampaignName'],
            'COST'        => $row['Cost'] / 1000000, // Direct returns values in microroubles
            'CLICKS'      => $row['Clicks'],
        ]);
    }
}

The same approach applies to VK Ads (ads.getStatistics) and Google Ads (Google Ads API, CampaignService).

ROI report in Bitrix24

The final report is built with a query joining spend and revenue:

SELECT
    d.UF_CRM_UTM_SOURCE as source,
    d.UF_CRM_CAMPAIGN_ID as campaign_id,
    SUM(ac.COST) as ad_spend,
    COUNT(DISTINCT d.ID) as deals_count,
    SUM(d.OPPORTUNITY) as revenue,
    ROUND((SUM(d.OPPORTUNITY) - SUM(ac.COST)) / NULLIF(SUM(ac.COST), 0) * 100, 1) as roi_pct
FROM b_crm_deal d
LEFT JOIN local_ad_costs ac
    ON ac.CAMPAIGN_ID = d.UF_CRM_CAMPAIGN_ID
    AND ac.SOURCE = d.UF_CRM_UTM_SOURCE
    AND DATE(ac.DATE) = DATE(d.DATE_CREATE)
WHERE d.STAGE_ID = 'WON'
    AND d.DATE_CLOSE BETWEEN :date_from AND :date_to
GROUP BY d.UF_CRM_UTM_SOURCE, d.UF_CRM_CAMPAIGN_ID
ORDER BY roi_pct DESC

The report is displayed in the Bitrix24 admin area or in an integrated BI tool (Yandex DataLens, Google Looker Studio).

Pushing spend back to Yandex Metrica

To display ROI directly in Metrica — upload spend via counter.uploadOfflineConversions (deprecated) or through the Data2 API. When end-to-end analytics runs through Metrica — connect via "Import spend data" from a CSV file generated by 1C-Bitrix.

Scope of work

  • Creating custom fields in Bitrix24 deals
  • Configuring UTM pass-through on lead creation (all channels)
  • Developing spend importers: Direct, VK Ads, Facebook/Instagram
  • local_ad_costs aggregation table
  • ROI report by campaign with period and channel filters
  • Cron schedule for import

Timeline: 1–2 weeks for a basic setup (Direct + one channel). 3–4 weeks for a multi-channel ROI report with a BI dashboard.