The standard Bitrix admin panel shows technical metrics—load, errors, module status. Business KPIs are not there: today's revenue, funnel conversion, average order value per manager are viewed in separate systems or even Excel. A dashboard with business KPIs embedded directly in Bitrix bridges this gap. We develop such dashboards turnkey: from SQL queries to visualization in the admin panel or a public page.
Which KPIs does business actually need?
Often managers ask for "all metrics," but real value lies in 5–6 key indicators. An e-commerce store needs revenue, conversion, average order value, top products. A wholesale distributor needs accounts receivable, overdue payments, manager workload. We help identify exactly those KPIs that drive decision making.
Why standard Bitrix reports are not enough?
Standard reports are snapshots at a request moment, without dynamics or period comparisons. There is no single window: revenue is viewed in 1C, conversion in Yandex.Metrica, workload in Personnel Management. A dashboard unifies this data in one interface, saving 2–3 hours a day on consolidation.
Dashboard architecture
The dashboard is implemented as a separate page in the admin section: /bitrix/admin/kpi_dashboard.php. Or as a public page in a restricted section—for manager access without rights to /bitrix/admin/.
Data is aggregated directly from the database via SQL—faster than sequential Bitrix API calls for each widget. Visualization uses Chart.js or ApexCharts, loaded as JS dependencies.
Key SQL queries for KPIs
Revenue over a period broken down by day:
SELECT DATE(o.date_insert) AS day,
COUNT(o.id) AS orders_count,
SUM(o.price) AS revenue,
AVG(o.price) AS avg_check
FROM b_sale_order o
WHERE o.lid = 's1'
AND o.canceled = 'N'
AND o.date_insert >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(o.date_insert)
ORDER BY day;Cart-to-order conversion:
WITH baskets AS (
SELECT DATE(date_insert) AS day, COUNT(DISTINCT fuser_id) AS basket_users
FROM b_sale_basket
WHERE site_id = 's1' AND date_insert >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(date_insert)
), orders AS (
SELECT DATE(date_insert) AS day, COUNT(DISTINCT user_id) AS order_users
FROM b_sale_order
WHERE lid = 's1' AND date_insert >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(date_insert)
)
SELECT b.day, b.basket_users, COALESCE(o.order_users, 0) AS order_users,
ROUND(COALESCE(o.order_users, 0)::NUMERIC / NULLIF(b.basket_users, 0) * 100, 2) AS conversion
FROM baskets b
LEFT JOIN orders o ON o.day = b.day
ORDER BY b.day;Top products by revenue:
SELECT ie.name AS product_name,
SUM(bi.quantity) AS qty_sold,
SUM(bi.price * bi.quantity) AS revenue
FROM b_sale_basket_item bi
JOIN b_sale_order_shipment_item si ON si.basket_id = bi.id
JOIN b_sale_order o ON o.id = bi.order_id
JOIN b_iblock_element ie ON ie.id = bi.product_id
WHERE o.canceled = 'N'
AND o.date_insert >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY ie.id, ie.name
ORDER BY revenue DESC
LIMIT 20; PHP widget implementation
Data is served via an AJAX endpoint and rendered with Chart.js:
// /local/ajax/kpi_data.php
if (!$USER->IsAdmin()) {
header('HTTP/1.1 403 Forbidden');
exit;
}
$widget = $_GET['widget'] ?? '';
$dateFrom = $_GET['date_from'] ?? date('Y-m-d', strtotime('-30 days'));
$dateTo = $_GET['date_to'] ?? date('Y-m-d');
$db = \Bitrix\Main\Application::getConnection();
switch ($widget) {
case 'revenue_chart':
$data = $db->query("
SELECT DATE(date_insert) as day, SUM(price) as revenue, COUNT(*) as cnt
FROM b_sale_order
WHERE lid = ? AND canceled = 'N' AND DATE(date_insert) BETWEEN ? AND ?
GROUP BY DATE(date_insert)
ORDER BY day
", [SITE_ID, $dateFrom, $dateTo])->fetchAll();
break;
case 'top_products':
// ... see query above
break;
}
header('Content-Type: application/json');
echo json_encode(['success' => true, 'data' => $data ?? []]);
// Initialize revenue chart
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
fetch(`/local/ajax/kpi_data.php?widget=revenue_chart&date_from=${encodeURIComponent(startDate.toISOString().slice(0,10))}`)
.then(r => r.json())
.then(({ data }) => {
const ctx = document.getElementById('revenueChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: data.map(d => d.day),
datasets: [{
label: 'Revenue, RUB',
data: data.map(d => d.revenue),
backgroundColor: '#4F81BD',
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false }
}
}
});
}); Case study: Dashboard for an electronics e-commerce store (our client)
The project is an e-commerce store with 4 managers, 50–80 orders per day. The goal: the manager wants real-time revenue, conversion, and manager workload. We implemented a dashboard with 6 widgets:
- Revenue today / yesterday / last week (numeric and % comparison)
- Revenue chart over 30 days (bar chart)
- Funnel: visitors → carts → orders (data from Bitrix + Yandex.Metrica API)
- Top 10 products by revenue for the period
- Manager workload: number of orders in progress per manager
- Unclosed orders older than 3 days (require attention)
The dashboard refreshes every 5 minutes via setInterval. Heavy aggregate queries are cached for 5 minutes with invalidation on order status changes. The project manager noted that the dashboard cut data analysis time by threefold.
Development time: 12 working days (SQL queries, PHP backend, dashboard layout, Metrica integration). Time saved for the manager: up to 10 hours per month on report preparation.
Common mistakes in dashboard development
- Queries without caching — with 10,000+ orders the page loads for 20+ seconds.
- Trying to fetch all data via
GetList()— on large volumes, this is disastrous. - Missing date filters — the dashboard is useless for analyzing trends.
- Unaccounted access rights — managers see others' orders.
We solve these issues at the design stage: use raw SQL, tagged caching, role-based model.
What is included in the work
| Component | Description |
|---|---|
| Technical specification | Description of metrics, data sources, layouts |
| Prototype | Interactive layout in the admin panel |
| Development | SQL queries, PHP endpoints, JS widgets |
| Integration | 1C, Yandex.Metrica, CRM (as needed) |
| Testing | Load testing with 1000+ orders |
| Documentation | Instructions for adding new widgets |
| Handover | Source code, caching access |
Timelines
| Scope | Duration |
|---|---|
| 3–4 widgets (revenue, orders, top products) | 4–6 days |
| 6–8 widgets + period filters | 8–12 days |
| Full dashboard + external source integration | 12–20 days |
Why choose us
Our engineers have over 10 years of experience in Bitrix and more than 50 dashboard projects. We are a certified 1C-Bitrix partner. We guarantee: the dashboard will not crash under peak load, data is fresh to within 5 minutes, visualization is responsive for any screen. The cost of development is determined after analysis.
We will evaluate your project for free. Contact us to discuss metrics and get a dashboard prototype within one day.

