v3.0.0

Pull (Push & Pull)

Real-time message stream from Bitrix24 to your application — WebSocket primary, long-polling fallback. Frame-only.
The Pull client is meant for frame applications (B24Frame) — it relies on the parent-window auth, channels, and member_id. It is not functional through B24Hook or B24OAuth on the server.

Overview

Pull lets the front-end of your application receive events the back-end (or another front-end instance) emits via the pull.application.event.add REST method. The SDK ships a complete client (B24PullClientManager) with two connectors:

  • WebSocket primary (ConnectionType.WebSocket)
  • Long-polling fallback (ConnectionType.LongPolling)
  • Protobuf-encoded message envelopes (decoders bundled, no extra dependency)

You normally drive Pull through useB24Helper — usePullClient / useSubscribePullClient / startPullClient are thin wrappers over the matching B24HelperManager methods.

Quick Start

import {
  initializeB24Frame,
  useB24Helper,
  Text,
  LoggerFactory,
  type B24Frame,
  type TypePullMessage
} from '@bitrix24/b24jssdk'

const $logger = LoggerFactory.createForBrowser('MyApp', import.meta.env?.DEV === true)
const {
  initB24Helper,
  getB24Helper,
  usePullClient,
  useSubscribePullClient,
  startPullClient,
  destroyB24Helper
} = useB24Helper()

let $b24: B24Frame

async function init() {
  $b24 = await initializeB24Frame()
  await initB24Helper($b24)

  // 1. Spin up the underlying B24PullClientManager (one per helper instance)
  usePullClient()

  // 2. Subscribe — can be called multiple times for multiple moduleIds
  useSubscribePullClient((message: TypePullMessage) => {
    $logger.info(`${Text.getDateForLog()} << pull`, { message })
  }, 'main')

  // 3. Connect (WebSocket → long-polling fallback)
  startPullClient()
}

async function emitPing(): Promise<void> {
  await $b24.actions.v2.call.make({
    method: 'pull.application.event.add',
    params: {
      COMMAND: 'ping',
      PARAMS: { tick: Text.getDateForLog() },
      MODULE_ID: getB24Helper().getModuleIdPullClient()
    }
  })
}

await init()
setInterval(emitPing, 5000)

When the host component unmounts, call destroyB24Helper() — that fully tears the Pull client down: closes the WebSocket, clears all subscriptions, removes its window listeners, and cancels all pending timers.

API via B24HelperManager

These four methods are the public Pull surface. See B24HelperManager.

usePullClient(prefix?: string, userId?: number): B24HelperManager
subscribePullClient(callback: (message: TypePullMessage) => void, moduleId?: string): B24HelperManager
startPullClient(): void
getModuleIdPullClient(): string
  • usePullClient constructs B24PullClientManager once. prefix is forwarded to b24.auth.getUniq(prefix) to derive restApplication. userId defaults to the loaded profile id.
  • subscribePullClient returns the helper for chaining; the unsubscribe handle is tracked internally and released on destroy().
  • startPullClient triggers PullClient.start() and logs the failure (without throwing) if the connection cannot be established.
  • getModuleIdPullClient returns the moduleId last passed to subscribePullClient. Use it as the MODULE_ID parameter of pull.application.event.add.

API via B24PullClientManager Directly

If you need finer control, instantiate the client yourself:

// @check-ignore: partial snippet — B24PullClientManager SubscriptionType not exported publicly

import { B24PullClientManager } from '@bitrix24/b24jssdk'

const pull = new B24PullClientManager({
  b24: $b24,
  restApplication: $b24.auth.getUniq('myApp'),
  userId: 1
})

const unsubscribe = pull.subscribe({
  type: 'server', // 'server' | 'client' | 'online'
  moduleId: 'main',
  command: 'optionsChanged',
  callback: (params) => console.log(params)
})

await pull.start()

// Later
unsubscribe()
pull.destroy()

subscribe() accepts either a full TypeSubscriptionOptions object (filter by type / moduleId / command) or a bare TypeSubscriptionCommandHandler function (catches any incoming command). It returns an unsubscribe callback.

Connection Types

The client picks the connector automatically:

  1. WebSocket — preferred when the portal exposes one.
  2. Long-polling — used when WebSocket is unavailable, blocked, or when the connection drops repeatedly.

ConnectionType (Undefined / WebSocket / LongPolling) and PullStatus (Online / Offline / Connecting) are exported from the package — useful if you want to reflect the connection in your UI.

Sending Messages

The Pull client only receives messages. To send, call pull.application.event.add over REST:

// @check-ignore: partial snippet — getB24Helper() not in scope

await $b24.actions.v2.call.make({
  method: 'pull.application.event.add',
  params: {
    COMMAND: 'optionsChanged',
    PARAMS: { theme: 'dark' },
    MODULE_ID: getB24Helper().getModuleIdPullClient()
  }
})

Subscribers attached via useSubscribePullClient(cb, 'main') will receive the matching TypePullMessage.

PullClient also exposes sendMessage() and sendMessageToChannels().sendMessage() is not the supported path in an application: it resolves the recipients' channels through pull.channel.public.list, which is not part of the application REST surface, and rejects with JSSDK_PULL_PUBLIC_IDS_UNAVAILABLE when it has to make that call. Use pull.application.event.add, as above.It does not always have to. The lookup is skipped when every recipient already has an unexpired channel in the cache, which the startup config call prefills from publicChannels — that map carries the current user's own channel, so a send addressed to yourself often goes out with no lookup and no rejection. It is still not a delivery receipt, and what comes back arrives on a SubscriptionType.Client subscription rather than the Server one subscribe() gives you by default.sendMessageToChannels() takes channel ids from the caller, so it never makes that lookup and never raises that code.Both reject with JSSDK_PULL_SEND_REFUSED when the transport will not take the frame, and JSSDK_PULL_PUBLISHING_DISABLED when the portal has not enabled client publishing. Until 3.0.0 all of these resolved as though the message had been sent — see the migration note.