Custom CRM Cards on Vue.js for Bitrix24

Problem: 1C data does not reach the deal card A client contacted us with a task: they needed to see the shipment status from 1C and a button to send an invoice directly in the deal card. Standard fields didn't cut it—they required customization. Often managers spent time manually transferring dat

Our competencies:

Frequently Asked Questions

Problem: 1C data does not reach the deal card

A client contacted us with a task: they needed to see the shipment status from 1C and a button to send an invoice directly in the deal card. Standard fields didn't cut it—they required customization. Often managers spent time manually transferring data, leading to errors and delays. We developed a Vue.js application embedded right into the card via the Bitrix24 placement mechanism. We work turnkey, evaluate your project within 1 day—contact us to discuss.

Problems we solve

  • Manual data transfer between 1C and Bitrix24, causing human errors and outdated information.
  • Missing business logic in standard fields: no way to trigger actions like “Send invoice” with a single click.
  • Performance bottlenecks when updating CRM fields one by one instead of using batch requests.

How we do it (technical deep dive)

Initialization

We start by initializing the application via BX24. After obtaining the entity ID and type (deal, contact, lead), we load data through the REST API. For 1C integration, we create a proxy endpoint that authenticates in 1C, fetches data, and returns JSON. Using Vue.js with Pinia speeds up development roughly 2–3 times compared to plain JavaScript on BX24.

import { createApp } from 'vue' import App from './App.vue' import { createPinia } from 'pinia' window.BX24.init(async () => { const placement = await getPlacement() const auth = BX24.getAuth() const app = createApp(App) app.use(createPinia()) app.provide('entityId', placement.ID) app.provide('entityType', placement.ENTITY_TYPE_NAME) app.provide('auth', auth) app.mount('#app') }) function getPlacement() { return new Promise(resolve => BX24.placement.getInterface(resolve)) } 

Loading entity data

We separate data loading into Pinia stores for clarity. The deal store handles both internal and external data.

import { defineStore } from 'pinia' import { inject } from 'vue' export const useDealStore = defineStore('deal', { state: () => ({ deal: null, relatedContacts: [], externalData: null, loading: false, }), actions: { async loadDeal(id) { this.loading = true const [deal, contacts] = await Promise.all([ bx24Call('crm.deal.get', { id }), bx24Call('crm.deal.contact.items.get', { id }), ]) this.deal = deal this.relatedContacts = contacts this.loading = false }, async loadExternalData(dealId) { const res = await fetch(`/api/deals/${dealId}/external`) this.externalData = await res.json() } } }) 

Updating card fields

To update deal fields, we use crm.deal.update. Avoid updating fields one by one in a loop—this creates a queue of requests and slows down the interface. Batch requests are preferred.

Displaying external data

A typical use case is showing a client's order history from 1C or ERP:

<template> <div class="external-orders"> <div v-if="store.loading" class="loader">Loading...</div> <table v-else> <thead> <tr> <th>Order number</th> <th>Date</th> <th>Amount</th> <th>Status</th> </tr> </thead> <tbody> <tr v-for="order in store.externalData?.orders" :key="order.id"> <td>{{ order.number }}</td> <td>{{ formatDate(order.date) }}</td> <td>{{ formatMoney(order.total) }}</td> <td> <span :class="statusClass(order.status)"> {{ order.statusLabel }} </span> </td> </tr> </tbody> </table> </div> </template> 

Custom buttons and actions

Add a button to the card toolbar using BX24.placement.bindEvent:

BX24.callMethod('placement.bind', { PLACEMENT: 'CRM_DEAL_DETAIL_TAB', HANDLER: 'https://my-app.example.com/', TITLE: 'My Tab', DESCRIPTION: 'CRM card extension', }) 
Common mistake: not handling authorization errors If the user is not authorized or the app lacks permissions, API calls will return an error. Always check `result.error()` and show a clear message.

Case study: Optimizing data loading

On one project, we reduced the data load time from 8 seconds to 1.2 seconds by switching from sequential REST calls to parallel batch requests and caching the 1C proxy response. This eliminated the “spinning wheel” in the card and improved manager productivity by 30%.

Process of evaluation and work

  1. Audit of current Bitrix24 processes and external systems.
  2. Architecture design – data flow, API endpoints, component tree.
  3. Development of the Vue.js application with Pinia.
  4. Integration with 1C or other external systems via REST API.
  5. Testing across all browsers and Bitrix24 modes (SPA, classic, mobile).
  6. Deployment and configuration of placement permissions.
  7. Documentation and manager training.
  8. Post-launch support for one month.

Timeline estimates

  • Simple tab with REST data: 2–4 days.
  • Full integration with external system: 1–3 weeks.

Cost is determined individually after evaluating the scope of work.

Comparison: Vue.js vs plain JavaScript

Criterion Vue.js + Pinia Plain JavaScript (jQuery)
Reactivity Automatic (templates update on data change) Manual (DOM updates)
Modularity Component approach, store Hard to maintain
Development speed 40% faster Slower
Scalability Easy to add new tabs and integrations Requires refactoring

Placement types overview

Placement type Context Example use
CRM_DEAL_DETAIL_TAB Deal card Client order history
CRM_CONTACT_DETAIL_TAB Contact card Additional communication channels
CRM_LEAD_DETAIL_TAB Lead card Lead source evaluation
CRM_DEAL_DETAIL_ACTIVITY Activity block “Send invoice” button

Why Vue.js is more efficient than plain JavaScript?

Vue.js with Pinia provides reactive data binding and a component architecture. This cuts development time by 40% and simplifies maintenance. Unlike plain JavaScript where every DOM change must be written manually, Vue.js automatically updates the UI when data changes. When scaling—adding new tabs or integrations—the code remains readable and modular.

What’s included in a custom CRM card development?

  • Audit of current Bitrix24 processes and external systems.
  • Application architecture and data schema design.
  • Vue.js application development with Pinia, including loading and displaying external data.
  • Configuration of actions and integration with 1C via REST API.
  • Cross-browser and multi-mode Bitrix24 testing.
  • Deployment, placement setup, and access rights.
  • Documentation and manager training.
  • One month of post-launch support.

Typical mistakes (and how we avoid them)

  • Ignoring batch requests: Updating fields one by one leads to API queue and poor UX. We always bundle updates.
  • Hardcoding variables in components: We use Pinia stores and provide/inject for clean state management.
  • Not handling visibility changes: When the tab is hidden, we stop loading to save resources; on return, we refresh if the data changed.

Get started

Our certified specialists with 10+ years of experience and 50+ completed Bitrix24 projects guarantee compatibility with the latest platform versions. Evaluation within 1 day—contact us to discuss your case. Request a consultation.

Learn more about placement in the official documentation: Bitrix24 REST API and Vue.js