Optimizing the number of HTTP requests in 1C-Bitrix

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

HTTP Request Count Optimization for 1C-Bitrix

Bitrix project audits regularly uncover pages with 180–250 HTTP requests on load. This is not an exaggeration: each component can add 2–4 CSS files and 3–5 JS files, plus icons as individual PNGs, plus analytics trackers, plus widgets. Every request involves DNS, TCP, TLS, and response headers. With HTTP/1.1, the browser maintains 6 parallel connections per domain. With HTTP/2, multiplexing helps, but does not eliminate overhead entirely.

Auditing the Current State

The first step is to measure, not guess. Tools:

  • Chrome DevTools → Network: Requests, Transferred, DOMContentLoaded, Load columns
  • WebPageTest (webpagetest.org): Waterfall diagram with grouping by type
  • Lighthouse: "Serve static assets with an efficient cache policy" + "Avoid chaining critical requests" metrics

Look at the waterfall for the longest dependency chains. The typical picture:

HTML → CSS (×5) → fonts (×6) → JS (×8) → images (×40+) → component Ajax requests (×3-5)

CSS and JS: Combiner and Bundling

Bitrix Built-in Combiner

In the main module settings (/bitrix/admin/settings.php?lang=ru) there are "Combine CSS files" and "Combine JS files" options. The combiner merges files into a single request /bitrix/cache/css/[hash].css. It works, but with caveats:

  • Only combines files from AddCSS() / AddHeadScript(), not inline component styles
  • When the cache is invalidated (any file is edited), the hash changes — browsers re-download
  • Does not minify CSS/JS — concatenation only

Webpack/Vite for Custom Assets

For your own code (not the Bitrix core), configure a bundler:

// vite.config.js
export default {
    build: {
        rollupOptions: {
            input: {
                main: 'local/templates/main/src/main.js',
                catalog: 'local/templates/main/src/catalog.js',
            }
        }
    }
}

You get 2 bundles instead of 15+ individual files. Splitting into main and catalog matters: do not load catalog JS on static pages.

Icons: Sprites and Inline SVG

Each icon as a separate file is the fastest way to accumulate 30–50 extra requests. Options:

SVG sprite — one file with all icons:

<!-- sprite.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
    <symbol id="icon-cart" viewBox="0 0 24 24">...</symbol>
    <symbol id="icon-search" viewBox="0 0 24 24">...</symbol>
</svg>

<!-- usage -->
<svg><use href="/local/templates/main/img/sprite.svg#icon-cart"></use></svg>

One HTTP request for all site iconography. Cached for a long time.

Inline SVG via a PHP helper for above-the-fold icons:

function svg(string $name): string {
    static $cache = [];
    if (!isset($cache[$name])) {
        $path = __DIR__ . '/icons/' . $name . '.svg';
        $cache[$name] = file_exists($path) ? file_get_contents($path) : '';
    }
    return $cache[$name];
}

Inline SVG = 0 HTTP requests, but increases HTML size.

Component Ajax Requests

Bitrix components with 'AJAX_MODE' => 'Y' make a separate XHR when navigating between catalog pages. This is normal, but on page initialization there are often several parallel Ajax requests to ajax.php with different parameters. The solution is batching: combine multiple requests into one using a queue:

// Accumulate requests for 50 ms, then send a batch
const queue = [];
function batchRequest(params) {
    queue.push(params);
    if (queue.length === 1) {
        setTimeout(() => {
            const batch = [...queue];
            queue.length = 0;
            fetch('/api/batch', {
                method: 'POST',
                body: JSON.stringify(batch)
            });
        }, 50);
    }
}

On the server side — an /api/batch endpoint that dispatches requests and returns an array of responses.

Images: Lazy Loading and Sprites

Catalog images are the largest source of requests. The minimum required:

// In the catalog.element component template
echo '<img src="' . $arItem['PREVIEW_PICTURE']['SRC'] . '"
           loading="lazy"
           width="' . $arItem['PREVIEW_PICTURE']['WIDTH'] . '"
           height="' . $arItem['PREVIEW_PICTURE']['HEIGHT'] . '"
           alt="' . htmlspecialchars($arItem['NAME']) . '">';

loading="lazy" — native lazy loading. The browser does not request images below the viewport until the user scrolls. On a catalog page with 48 cards, this removes 30–40 requests from the critical path.

Case Study: Marketplace Optimization

An electronics online store on Bitrix "E-Commerce": home page — 214 HTTP requests, Load time 8.3 s.

What was done step by step:

  1. Enabled CSS/JS combiner → -18 requests
  2. Built an SVG sprite from 64 icons → -63 requests
  3. Added loading="lazy" to all below-fold images → -41 requests from the critical path
  4. Moved Google Analytics and Yandex.Metrica to defer → removed from blocking path
  5. Merged 5 custom JS files into 1 bundle via Vite → -4 requests

Result: 214 → 88 requests, Load time: 8.3 s → 3.1 s, LCP: 5.2 s → 1.9 s.

HTTP/2 Push and Preload

With HTTP/2, resources can be announced via the Link: <url>; rel=preload response header. In Nginx:

location = / {
    add_header Link "</local/templates/main/fonts/roboto-400.woff2>; rel=preload; as=font; crossorigin";
    add_header Link "</local/templates/main/css/main.css>; rel=preload; as=style";
}

This does not reduce the number of requests, but shortens the waterfall — the browser learns about resources earlier.

Timeline

Scale Scope Duration
Basic Combiner, lazy loading, defer for trackers 1–2 days
Medium SVG sprite, Vite bundling for custom code, HTTP/2 4–7 days
Full Batch API for Ajax, full audit and elimination of all redundant requests 8–14 days