Developing Embedded Applications on Vue.js for Bitrix24
Embedded applications in Bitrix24 are standalone frontend modules that load inside the portal interface via iframe or the BX24 JS SDK. The standard approach is a PHP page with window.BX24.init() and jQuery code. When the application logic becomes non-trivial — multiple screens, state management, reactive updates — jQuery turns into unmaintainable spaghetti. Vue.js solves this problem architecturally.
How Applications Are Embedded in Bitrix24
Bitrix24 provides two placement mechanisms:
-
iframe application — loaded from an external URL in the portal window. Exchanges data with Bitrix24 through the
window.BX24JS library. -
Embedded JS application — hosted on the same domain, registered via
\Bitrix\Rest\AppTable, uses the server REST API directly.
For Vue applications, the standard choice is an iframe with separate hosting or placement in /local/apps/. The server-side can be written in Laravel, Node.js, or Bitrix itself.
Initializing Vue Inside Bitrix24
Connecting the BX24 SDK and starting the Vue application:
<!-- index.html -->
<script src="//{{portal}}.bitrix24.ru/bitrix/js/rest/bx24/bx24.js"></script>
<div id="app"></div>
<script type="module" src="/assets/app.js"></script>
// main.js
import { createApp } from 'vue'
import App from './App.vue'
window.BX24.init(() => {
const app = createApp(App)
app.provide('bx24', window.BX24)
app.mount('#app')
})
Passing BX24 via provide/inject allows it to be used in any component without global variables.
Working with the Bitrix24 REST API from Vue
For REST calls, BX24.callMethod or BX24.callBatch is used. Wrapping them in promises:
// composables/useBx24.js
import { inject } from 'vue'
export function useBx24() {
const bx24 = inject('bx24')
function callMethod(method, params = {}) {
return new Promise((resolve, reject) => {
bx24.callMethod(method, params, (result) => {
if (result.error()) reject(result.error())
else resolve(result.data())
})
})
}
async function callBatch(calls) {
return new Promise((resolve, reject) => {
bx24.callBatch(calls, (results) => {
const errors = Object.values(results).filter(r => r.error())
if (errors.length) reject(errors[0].error())
else resolve(Object.fromEntries(
Object.entries(results).map(([k, v]) => [k, v.data()])
))
})
})
}
return { callMethod, callBatch }
}
A typical deals list component:
<script setup>
import { ref, onMounted } from 'vue'
import { useBx24 } from '@/composables/useBx24'
const { callMethod } = useBx24()
const deals = ref([])
const loading = ref(true)
onMounted(async () => {
deals.value = await callMethod('crm.deal.list', {
select: ['ID', 'TITLE', 'STAGE_ID', 'OPPORTUNITY'],
filter: { STAGE_ID: 'NEW' },
order: { DATE_CREATE: 'DESC' }
})
loading.value = false
})
</script>
Managing iframe Size
Bitrix24 does not manage iframe height automatically. The application must report its own size:
// App.vue
import { onMounted, onUpdated } from 'vue'
const bx24 = inject('bx24')
function fitWindow() {
bx24.fitWindow()
}
onMounted(fitWindow)
onUpdated(fitWindow)
For dynamic applications with variable height — a ResizeObserver on the root element calling bx24.resizeWindow(width, height).
Authorization and Access Rights
The access token is passed automatically via the BX24 SDK. For server-side requests, bx24.getAuth() is used:
const auth = bx24.getAuth()
// { access_token, expires_in, scope, domain, ... }
await fetch('/api/my-endpoint', {
headers: { Authorization: `Bearer ${auth.access_token}` }
})
Checking user permissions — crm.contact.access.has and similar methods depending on the entity.
Build and Deployment
Vite is the optimal build choice:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
base: '/local/apps/my-app/',
build: {
outDir: 'dist',
assetsDir: 'assets',
}
})
The built dist/ is placed on the server. The entry point URL is specified in the Bitrix24 application settings. For local development, ngrok or a Vite dev server with HTTPS is used — Bitrix24 requires HTTPS for iframe applications.
Typical Use Cases
Deals dashboard — aggregating CRM data, visualizing the funnel, filtering by responsible persons and periods. Standard Bitrix24 reports are insufficient for custom data slices.
Custom lead creation form — a multi-step form with validation, dependent fields, and file uploads. The standard CRM card does not support complex conditional field display logic.
Integration connector — the application retrieves data from an external system (1C, ERP, marketplace) and displays it in the Bitrix24 context with synchronization capability.
Task planner — a custom UI for managing tasks with drag-and-drop, a kanban board, or a timeline view on top of the standard tasks API.
Timeline
A simple application (one screen, CRUD for a single entity) — 2–3 business days. An application with multiple screens, authorization, a server-side component, and deployment — 1–2 weeks depending on the complexity of the business logic.







