Custom Vue.js Dashboards for Bitrix24: Funnels, KPIs, and Reports

Custom Vue.js Dashboards for Bitrix24: Funnels, KPIs, and Reports Built-in Bitrix24 analytics covers standard scenarios: sales funnel, manager report, plan/actual. As soon as a business analyst comes with a request like "show me conversion by source in the context of regions for an arbitrary peri

Our competencies:

Frequently Asked Questions

Custom Vue.js Dashboards for Bitrix24: Funnels, KPIs, and Reports

Built-in Bitrix24 analytics covers standard scenarios: sales funnel, manager report, plan/actual. As soon as a business analyst comes with a request like "show me conversion by source in the context of regions for an arbitrary period with a filter by responsible person" — standard reports end. A custom analytics interface (Vue-based dashboard) is a tailored solution embedded into Bitrix24 via an iframe application with direct access to the REST API. We handle such projects turnkey and have already implemented over 20 projects for companies of various sizes. These dashboards save up to 40% of managers' time on data collection and allow seeing business metrics in real time.

Why is a Vue.js dashboard more effective than standard reports?

Standard Bitrix24 analytics provides fixed slices: plan/actual, funnel, manager report. But for deep analysis — conversion by source in the context of regions, comparison of dynamics by month, custom metrics — you have to export data to Excel and process manually. A Vue-based dashboard solves this: data is fetched via REST API, aggregated on the client or server, and displayed in interactive charts. According to our measurements, such a dashboard processes requests 3 times faster than a standard report with several filters. The user gets a decision-making tool: they see sales dynamics, funnel conversion, manager efficiency in real time. Data updates automatically, filters allow viewing any period. Without modifications to the standard CRM.

Dashboard Architecture

The dashboard consists of three layers:

  • Data layer — queries to Bitrix24 REST API, caching, aggregation. For heavy aggregations, we use an intermediate server layer (Node.js/PHP) that merges data from several REST calls and returns a ready JSON.
  • Storage layer — Pinia stores with reactive computed properties.
  • Presentation layer — Vue components with Chart.js or ApexCharts.

How to speed up data loading for the dashboard?

Bitrix24 REST API has a limit of 50 elements per request. To fetch all deals for a period, pagination or callBatch is needed. We use batch data collection with pagination and server-side caching. According to the official Bitrix24 REST API documentation, the limit per request is 50 records, so we bypass this using callBatch in composable functions.

// composables/useCrmData.js export function useCrmData() { const { callMethod } = useBx24() async function fetchAllDeals(filter) { const allDeals = [] let start = 0 let hasMore = true while (hasMore) { const result = await callMethod('crm.deal.list', { select: ['ID', 'TITLE', 'STAGE_ID', 'OPPORTUNITY', 'SOURCE_ID', 'ASSIGNED_BY_ID', 'DATE_CREATE', 'UF_CRM_REGION'], filter, order: { ID: 'ASC' }, start, }) allDeals.push(...result) hasMore = result.length === 50 start += 50 } return allDeals } async function fetchDealsByStages(filter) { const [deals, stages] = await Promise.all([ fetchAllDeals(filter), callMethod('crm.status.list', { filter: { ENTITY_ID: 'DEAL_STAGE' } }) ]) return { deals, stages } } return { fetchAllDeals, fetchDealsByStages } } 

Period Filter Component

The date filter is one of the key dashboard elements. We implement it on Vue 3 using date-fns.

<!-- components/DateRangeFilter.vue --> <template> <div class="filter-bar"> <div class="filter-presets"> <button v-for="preset in presets" :key="preset.id" :class="{ active: activePreset === preset.id }" @click="applyPreset(preset)" >{{ preset.label }}</button> </div> <div class="filter-custom"> <input type="date" v-model="dateFrom" @change="emitCustomRange" /> <input type="date" v-model="dateTo" @change="emitCustomRange" /> </div> </div> </template> <script setup> import { ref } from 'vue' import { startOfMonth, endOfMonth, subMonths, format } from 'date-fns' const emit = defineEmits(['change']) const activePreset = ref('current_month') const dateFrom = ref('') const dateTo = ref('') const presets = [ { id: 'current_month', label: 'Current month' }, { id: 'prev_month', label: 'Previous month' }, { id: 'quarter', label: 'Quarter' }, { id: 'year', label: 'Year' }, ] function applyPreset(preset) { activePreset.value = preset.id const now = new Date() let from, to switch (preset.id) { case 'current_month': from = startOfMonth(now) to = endOfMonth(now) break case 'prev_month': from = startOfMonth(subMonths(now, 1)) to = endOfMonth(subMonths(now, 1)) break // ... } emit('change', { from: format(from, 'yyyy-MM-dd'), to: format(to, 'yyyy-MM-dd'), }) } </script> 

Integrating Chart.js

For creating charts, we use a composable that initializes Chart.js and updates it when the configuration changes.

// composables/useChart.js import { onMounted, onUnmounted, ref, watch } from 'vue' import Chart from 'chart.js/auto' export function useChart(canvasRef, config) { let chart = null onMounted(() => { chart = new Chart(canvasRef.value, config.value) }) watch(config, (newConfig) => { if (!chart) return chart.data = newConfig.data chart.update('active') }, { deep: true }) onUnmounted(() => chart?.destroy()) } 

Sales funnel component with horizontal bars:

<template> <div class="chart-card"> <h3>Sales Funnel</h3> <canvas ref="canvasRef" height="300"></canvas> </div> </template> <script setup> import { ref, computed } from 'vue' import { useDashboardStore } from '@/stores/dashboard' import { useChart } from '@/composables/useChart' const store = useDashboardStore() const canvasRef = ref(null) const chartConfig = computed(() => ({ type: 'bar', data: { labels: store.stages.map(s => s.NAME), datasets: [{ label: 'Number of deals', data: store.stages.map(s => store.dealsByStage[s.STATUS_ID] || 0), backgroundColor: store.stages.map(s => s.COLOR || '#4a90d9'), }] }, options: { indexAxis: 'y', responsive: true, plugins: { legend: { display: false } } } })) useChart(canvasRef, chartConfig) </script> 

KPI Cards

Aggregating metrics on the client using Pinia computed:

// stores/dashboard.js const kpis = computed(() => { const deals = filteredDeals.value const won = deals.filter(d => d.STAGE_ID === 'WON') const total = deals.length return { totalDeals: total, wonDeals: won.length, conversionRate: total ? Math.round((won.length / total) * 100) : 0, totalRevenue: won.reduce((sum, d) => sum + parseFloat(d.OPPORTUNITY || 0), 0), avgDealSize: won.length ? won.reduce((sum, d) => sum + parseFloat(d.OPPORTUNITY || 0), 0) / won.length : 0, } }) 

Performance

Dashboards with large data volumes require optimization:

  • Server-side aggregation — do not transfer 10,000 deals to the browser.
  • shallowRef for large arrays in Pinia — deep reactivity for each object is not needed.
  • Table virtualization — @tanstack/vue-virtual for lists > 500 rows.
  • Debounce on filters — 300–500 ms before making a request.

Chart Library Comparison

Library Chart types Performance License
Chart.js 8 basic High up to 1k points MIT
ApexCharts 15+ (including heatmaps) Medium up to 10k points MIT
ECharts 20+ High up to 100k points Apache 2.0

For most dashboards, Chart.js is suitable, but if complex dashboards with large data are needed, we use ApexCharts or ECharts.

Data Fetching Methods Comparison

Method Speed Limits
Direct REST Medium 50 records
callBatch Fast 50 per request
Server proxy High None

Development Process and Guarantees

The process includes:

  1. Metric analysis and requirement gathering – define KPIs and data sources.
  2. Layout and wireframe design – approve dashboard mockups.
  3. Development on Vue 3 + Pinia stack – build reusable components.
  4. Integration with Bitrix24 REST API – implement data fetching and caching.
  5. Performance testing on real data – optimize for speed.
  6. Deployment to the cloud or Bitrix24 server.
  7. Handover of documentation, access, and training for analysts.

The cost includes:

  • Dashboard development according to your requirements.
  • Integration with Bitrix24 REST API, caching setup.
  • Interface assembly using Vue.js, Pinia, Chart.js/ApexCharts.
  • Testing on real data, query optimization.
  • Documentation, code access, user training.
  • 6-month warranty on functionality.

What's Included in the Work

  • Custom dashboard design and development
  • Integration with Bitrix24 REST API
  • Data caching and aggregation setup
  • Interactive charts using Chart.js or ApexCharts
  • Complete documentation and source code
  • User training for analysts
  • 6-month warranty on all functionality
  • Ongoing support options available

Cost Savings and ROI

Clients report saving up to 30 hours per month per manager by automating reporting, translating to thousands of dollars annually. For example, a mid-sized company with 10 sales managers can save over $50,000 per year in analyst time. Typical project investment ranges from $1,500 for a basic dashboard to $15,000 for a full analytical portal, with an average payback period of 3 months.

Timeline

A dashboard with 3–5 widgets (funnel, KPI cards, period dynamics) — 5–8 business days. A full analytical portal with many widgets, server-side aggregation, export, and access roles — 3–5 weeks. Order development — get a consultation on timelines and scope.

Additional resources: Vue.js and Chart.js are proven tools for dashboards.