v1.2.0

Recipe: Subscribe to Pull events

Open a live channel from a Bitrix24 frame app and react to push events using useB24Helper + the Pull client.
We are still updating this page. Some data may be missing here — we will complete it shortly.

Goal

A frame app that gets real-time updates from Bitrix24 — for example, the badge counter goes up when a new chat message arrives or when a CRM activity changes hands. The Pull client multiplexes WebSocket and long-polling transports; you only see one callback.

Stack & Prerequisites

  • Vue 3 + Vite (or Nuxt) running inside a Bitrix24 placement
  • @bitrix24/b24jssdk@^1.0.0
  • The portal must have the Pull module enabled (it is on every cloud and most on-premise installations)
pnpm add @bitrix24/b24jssdk

Full Example

src/components/PullPanel.vue:

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
import {
  initializeB24Frame,
  LoadDataType,
  LoggerFactory,
  useB24Helper,
  type B24Frame,
  type TypePullMessage
} from '@bitrix24/b24jssdk'

const logger = LoggerFactory.createForBrowser('PullPanel', import.meta.env.DEV)
const events = ref<Array<{ at: string, command: string }>>([])
let $b24: B24Frame | null = null

const {
  initB24Helper,
  destroyB24Helper,
  usePullClient,
  useSubscribePullClient,
  startPullClient
} = useB24Helper()

function handleEvent(message: TypePullMessage) {
  logger.info('pull', message)
  events.value.unshift({
    at: new Date().toLocaleTimeString(),
    command: message.command
  })
  // Keep the visible log short.
  if (events.value.length > 20) events.value.length = 20
}

onMounted(async () => {
  $b24 = await initializeB24Frame()

  // App + Profile are required so the helper can register a Pull channel.
  await initB24Helper(
    $b24,
    [LoadDataType.App, LoadDataType.Profile],
    'pull-panel-init'
  )

  usePullClient()
  // Listen to events from the `crm` module. Use `'application'` (default) for
  // your own app's custom events.
  useSubscribePullClient(handleEvent, 'crm')
  startPullClient()
})

onBeforeUnmount(() => {
  destroyB24Helper()
  $b24 = null
})
</script>

<template>
  <section>
    <h2>Live events</h2>
    <ul v-if="events.length">
      <li v-for="(event, index) in events" :key="index">
        <code>{{ event.at }}</code> — {{ event.command }}
      </li>
    </ul>
    <p v-else>Waiting for events…</p>
  </section>
</template>

Run It

Open the app inside Bitrix24, then trigger a CRM event in another tab — drag a deal to a new stage, add an activity, change the responsible person. Within a second the event command (e.g. crm_deal_update) appears at the top of the list. The component keeps the last 20 events visible.

How It Works

  • useB24Helper() returns a closure over a single B24HelperManager instance. It is not a Vue composable — it doesn't read Vue lifecycle hooks. You wire it into onMounted / onBeforeUnmount yourself.
  • initB24Helper($b24, dataTypes, requestId) loads the data the Pull client needs to register a channel. Without LoadDataType.App and LoadDataType.Profile the subsequent usePullClient() call throws.
  • usePullClient() instantiates the Pull transport (WebSocket with long-polling fallback). useSubscribePullClient(handler, moduleId) registers your callback for that module. startPullClient() actually opens the connection — call it last.
  • destroyB24Helper() tears down the transport and unregisters subscribers. Calling it on unmount prevents the WebSocket from leaking when the app slider closes.

Limitations

  • The order must be initB24HelperusePullClientuseSubscribePullClientstartPullClient. Calling useSubscribePullClient before usePullClient throws PullClient is not initialized. The error is intentional — it surfaces wiring mistakes early.
  • useB24Helper() returns one shared instance per closure. If you create a second useB24Helper() and call initB24Helper again, the second call re-uses the existing manager rather than building a new one.
  • moduleId defaults to 'application'. To listen to portal modules ('crm', 'tasks', 'im', …) pass them explicitly. Subscribing to multiple modules requires multiple useSubscribePullClient calls.
  • Pull events are best-effort. They are great for "wake the UI up", not for "this is the source of truth". Always re-fetch via REST when the user takes an action that depends on freshness.

See also