When a mass email campaign launched, the landing page on a website builder crashed — the server couldn't handle 5,000 concurrent visitors. A promo site on 1C-Bitrix with nginx FastCGI caching and infoblocks handles such peaks without losing conversions. A custom CMS gives full control: from layout to CRM integration. One concrete case: for a telecom client, we built a promo page that attracted 12,000 leads in 3 days — the average cost per lead dropped by 30%. Marketers saved 40% of the budget by eliminating external analytics services.
Technically, a promo site on Bitrix is a single-page site with sections, lead capture forms, and integration with Bitrix24 via the REST API. We use infoblock v2.0 for content, highload blocks for A/B test statistics, and tagged caching for speed. This approach is 5 times faster than a typical landing page on a builder under peak loads.
When to use a promo on Bitrix instead of a builder
- The main site is already on Bitrix — the promo is placed on a subdomain or in a folder, using the same template and cache. Integration takes 2 hours.
- CRM is needed without intermediaries — forms immediately create leads in Bitrix24 via the API, capturing UTM tags.
- The promo will be used repeatedly (campaigns, events) — content changes through the admin panel without a developer.
- A/B testing with built-in tools is required — no need for external services.
Promo site architecture
Two approaches:
-
Separate template on the main site. Create a template
/local/templates/promo_EVENTNAME/— minimal wrapper without navigation. The page/promo/event-name/index.phpconnects to it via$APPLICATION->SetTemplate(). -
Separate site in a multisite setup. If the promo is on a subdomain
promo.example.ru— create a new site in the admin panel (Settings → Sites → Site list). Its own template, settings, and mail events.
Editable sections via infoblock
To let marketers change content, we place blocks via the promo_sections infoblock.
Element properties: section type (hero, features, testimonials, cta, faq), background, CTA text. In the template, switch on SECTION_TYPE:
$sections = \CIBlockElement::GetList( ['SORT' => 'ASC'], ['IBLOCK_ID' => PROMO_SECTIONS_IBLOCK_ID, 'ACTIVE' => 'Y', 'PROPERTY_PROMO_ID' => $promoId], false, false, ['ID', 'NAME', 'CODE', 'DETAIL_TEXT', 'PROPERTY_SECTION_TYPE', 'PROPERTY_BG_IMAGE', 'PROPERTY_CTA_TEXT', 'PROPERTY_CTA_URL'] ); while ($section = $sections->GetNext()) { $sectionType = $section['PROPERTY_SECTION_TYPE_VALUE']; $sectionFile = __DIR__ . '/sections/' . $sectionType . '.php'; if (file_exists($sectionFile)) { include $sectionFile; } } Lead capture forms
On the promo site, there are several conversion points: hero form, bottom form, exit-intent popup. All send requests to one handler:
\Bitrix\Main\Loader::includeModule('crm'); $promoId = htmlspecialchars($_POST['promo_id'] ?? ''); $name = htmlspecialchars(trim($_POST['name'] ?? '')); $phone = htmlspecialchars(trim($_POST['phone'] ?? '')); $email = htmlspecialchars(trim($_POST['email'] ?? '')); $source = htmlspecialchars($_POST['form_position'] ?? 'unknown'); // hero | bottom | popup if (empty($phone) && empty($email)) { echo json_encode(['error' => 'Provide a phone or email']); exit; } $lead = new \CCrmLead(false); $leadId = $lead->Add([ 'TITLE' => 'Promo: ' . $promoId . ' — ' . $name, 'NAME' => $name, 'PHONE' => [['VALUE' => $phone, 'VALUE_TYPE' => 'WORK']], 'EMAIL' => [['VALUE' => $email, 'VALUE_TYPE' => 'WORK']], 'SOURCE_ID' => 'WEB', 'SOURCE_DESCRIPTION' => 'Promo: ' . $promoId . ', form: ' . $source, 'UTM_SOURCE' => $_COOKIE['utm_source'] ?? '', 'UTM_MEDIUM' => $_COOKIE['utm_medium'] ?? '', 'UTM_CAMPAIGN' => $_COOKIE['utm_campaign'] ?? '', ]); echo json_encode(['success' => (bool)$leadId]); UTM tags are stored in cookies for 30 minutes via JavaScript and passed to the lead. The fields UTM_SOURCE, UTM_MEDIUM, UTM_CAMPAIGN, UTM_TERM, UTM_CONTENT are available — we use them. As indicated in the REST API documentation, the CCrmLead::Add method creates a lead in a single request.
How to implement a countdown timer?
A timer leading up to the end of a promotion is a key conversion element. We implement it with JavaScript and server-side time:
// Date from infoblock settings, no hardcoding $promoEndDate = \COption::GetOptionString('promo', 'end_date'); echo '<script>window.PROMO_END_DATE = "' . $promoEndDate . '";</script>'; function startCountdown(endDateStr) { const endDate = new Date(endDateStr); const timer = setInterval(() => { const now = new Date(); const diff = endDate - now; if (diff <= 0) { clearInterval(timer); document.getElementById('timer').textContent = 'Promotion ended'; return; } const days = Math.floor(diff / 86400000); const hours = Math.floor((diff % 86400000) / 3600000); const minutes = Math.floor((diff % 3600000) / 60000); const seconds = Math.floor((diff % 60000) / 1000); document.getElementById('timer-days').textContent = String(days).padStart(2, '0'); document.getElementById('timer-hours').textContent = String(hours).padStart(2, '0'); document.getElementById('timer-minutes').textContent = String(minutes).padStart(2, '0'); document.getElementById('timer-seconds').textContent = String(seconds).padStart(2, '0'); }, 1000); } Why add A/B testing?
A/B tests let you compare page variants without external services. We split visitors via cookie:
if (!isset($_COOKIE['promo_variant'])) { $variant = rand(0, 1) ? 'A' : 'B'; setcookie('promo_variant', $variant, time() + 86400 * 30, '/'); } else { $variant = $_COOKIE['promo_variant']; } $templateFile = __DIR__ . '/variants/' . $variant . '.php'; include $templateFile; Results are written to a separate table b_local_promo_ab_stats with fields PROMO_ID, VARIANT, VIEWS, CONVERSIONS. After 1,000 visitors per variant, statistical significance becomes visible — the better variant can be chosen.
When is an A/B test considered complete?
After accumulating 1,000 visitors per variant, you can evaluate statistical significance. If the conversion difference exceeds 5%, the leading variant is declared the winner.Caching and performance
A promo site might face peak traffic: 10,000 visitors per hour from a newsletter. We configure:
- Full-page caching via nginx FastCGI cache for anonymous users. Page delivery time — 0.002 s.
- Cache-Control: public, max-age=3600 for static assets.
- Cache warming after each deployment.
- Rate limiting for AJAX requests (nginx
limit_req_zone).
How to launch a promo site in 5 steps?
- Define goals and audit the current site.
- Design the infoblock architecture and integrations.
- Develop the template, forms, timer, and A/B test.
- Load testing and caching configuration.
- Launch and hand over editing instructions.
What's included in the work
| Stage | Description |
|---|---|
| Analysis and specification | Define goals, audit the current site, select a template |
| Design | Infoblock architecture, CRM integration scheme |
| Development | Layout, programming components, forms, timers |
| Testing | Peak load testing, UTM analytics, A/B test |
| Launch and training | Caching setup, provide access, editor instructions |
Our team has 5+ years of experience in Bitrix development and over 50 delivered promo sites. We guarantee quality and set deadlines in the contract. Get an engineer consultation to evaluate your project. Contact us for a cost estimate.
Development timelines
| Option | Scope | Timeline |
|---|---|---|
| Landing from a ready layout | Layout + form + lead to CRM | 3–5 days |
| With editable content | + Infoblock sections, admin panel management | 5–8 days |
| Full-featured promo | + Timer, A/B test, UTM analytics | 8–14 days |
The cost is calculated individually and fixed in the contract.

