Analytics Dashboard Development on Vue.js for 1C-Bitrix
Standard reports in the Bitrix admin panel are static HTML tables generated on every page refresh. For real-time business performance monitoring this is not enough: you can't change the period without a reload, there's no trend visualization, and data from multiple sources isn't aggregated. Vue.js combined with Chart.js or ECharts transforms Bitrix data into a live dashboard.
Where the Data Comes From
Bitrix stores everything needed in the database: orders in b_sale_order, line items in b_sale_basket, payments in b_sale_pay_system_action, customers in b_user. The D7 ORM lets you build aggregating queries directly via DataManager:
$result = \Bitrix\Sale\Internals\OrderTable::getList([
'select' => [
new \Bitrix\Main\ORM\Fields\ExpressionField(
'TOTAL', 'SUM(%s)', 'PRICE'
),
new \Bitrix\Main\ORM\Fields\ExpressionField(
'COUNT', 'COUNT(*)', 'ID'
),
'DATE_KEY' => 'DATE_INSERT',
],
'filter' => [
'>=DATE_INSERT' => $dateFrom,
'<=DATE_INSERT' => $dateTo,
'=STATUS_ID' => ['N', 'P', 'F'],
],
'group' => ['DATE_KEY'],
]);
A custom REST controller (extending Bitrix\Main\Engine\Controller) accepts period parameters and returns aggregated JSON. The controller is gated behind checkPermissions — only users with the sale_order_view right.
Vue Dashboard Structure
The dashboard is built from independent widgets — each Widget*.vue component loads its own data and displays its own loading state. The parent Dashboard.vue only manages the shared period via provide/inject.
Key widgets:
-
RevenueChart— line or bar chart of revenue over time (Chart.jsline) -
OrdersKpi— KPI cards: revenue, order count, average order value, conversion rate -
TopProducts— horizontal bar chart of the top 10 products by sales -
FunnelWidget— funnel: visitors → added to cart → placed order → paid -
OrdersTable— latest orders with pagination, quick link to the order in the admin panel
Global period filter — DatePicker with preset ranges ("Today", "This week", "This month", "Last month", "Custom"). When the period changes, all widgets react via watchEffect or watch on period from inject and reload their data.
Integration with Multiple Sources
A real dashboard is rarely limited to a single system. A typical data stack for e-commerce on Bitrix:
-
Orders and revenue —
b_sale_order,b_sale_basketvia D7 - Traffic — Yandex.Metrika API or Google Analytics 4 Data API
-
CRM metrics — if the
crmmodule is installed,CCrmDeal::GetListorBitrix\Crm\DealTable - Ad spend — Yandex.Direct API, VK Ads API, if integrations are configured
In Vue each source is a separate composable:
// useMetrikaData.js
export function useMetrikaData(period) {
const data = ref(null);
const loading = ref(false);
const error = ref(null);
watchEffect(async () => {
loading.value = true;
try {
data.value = await fetchMetrika(period.value);
} catch (e) {
error.value = e.message;
} finally {
loading.value = false;
}
});
return { data, loading, error };
}
Parallel requests via Promise.all — the dashboard doesn't wait for each source sequentially.
Case: Dashboard for an Online Store Manager
An electronics store on Bitrix, 200–400 orders per day. The problem: the director asked managers every day to compile a report from 1C, the Bitrix panel, and Metrika. The process took 40 minutes.
We built a dashboard accessible at /area51/dashboard/sales/ (in the Bitrix admin area, behind authentication). Technically — an admin section page via CAdminSection, on which a Vue application is mounted.
Widgets: today's/yesterday's/7-day revenue with a trend arrow, order count by status (new/processing/completed/cancelled), top 5 products for the period, two-period comparison on a single chart, abandoned cart rate (b_sale_basket where ORDER_ID IS NULL).
Abandoned cart data — a custom query not available in Bitrix's standard reports:
SELECT DATE(DATE_INSERT) as day, COUNT(DISTINCT FUSER_ID) as abandoned
FROM b_sale_basket
WHERE ORDER_ID IS NULL
AND DATE_INSERT >= NOW() - INTERVAL 30 DAY
GROUP BY day
The dashboard auto-refreshes every 5 minutes via setInterval — up-to-date data without pressing F5. Development time — 3 weeks, including all widgets and Metrika integration.
Query Performance
Aggregating queries on b_sale_order on large databases (100K+ orders) require indexes. Check with EXPLAIN:
-
DATE_INSERT— index is mandatory for period filtering - Composite index
(STATUS_ID, DATE_INSERT)— for filtering by status and period simultaneously - Results of heavy aggregations are cached via
Bitrix\Main\Data\Cachefor 5–15 minutes
Stages and Timelines
| Dashboard scale | Estimated timeline |
|---|---|
| 3-4 KPI cards + one chart | 3-5 days |
| Full sales dashboard (5-8 widgets) | 2-3 weeks |
| Dashboard with external API integration (Metrika, CRM) | 3-5 weeks |
| Analytics platform with multiple roles | 6-10 weeks |
Timelines depend on the number of data sources, aggregation complexity, and custom visualization requirements.







