v2.1.0

B24Frame Class

Designed for managing Bitrix24 applications running inside a placement iframe. Inherits from AbstractB24 and exposes managers for authentication, parent-window messaging, sliders, dialogs, placements, and options.
You should not call new B24Frame(...) directly — use initializeB24Frame(), which deduplicates concurrent inits, parses the window.name payload from Bitrix24, and awaits init() for you.

B24Frame extends AbstractB24 and implements TypeB24. On top of the shared REST surface (actions.v2.*, actions.v3.*, tools.*) it exposes managers that talk to the parent window through postMessage: auth, parent, slider, dialog, placement, options.

Constructor

constructor(
  queryParams: B24FrameQueryParams,
  options?: { restrictionParams?: Partial<RestrictionParams> }
)

B24FrameQueryParams describes the Bitrix24-supplied identifiers parsed from window.name:

FieldTypeDescription
DOMAINstringBitrix24 portal domain.
PROTOCOLbooleanConnection protocol flag.
LANGstringBitrix24 interface language.
APP_SIDstringApplication session identifier.

Unlike B24Hook and B24OAuth, B24Frame requires await b24.init() before any REST call — init() performs the getInitData handshake with the parent window. initializeB24Frame() does this for you.

Getters

isInit

get isInit(): boolean

true once the parent-window handshake completes. Until then, accessing auth, actions, tools, or any frame manager throws 'B24 not initialized'.

isFirstRun

get isFirstRun(): boolean

true on the very first launch of the application (Bitrix24 sets FIRST_RUN). On isFirstRun = true, the SDK automatically sends setInstall: true to the parent.

isInstallMode

get isInstallMode(): boolean

true while the application is in installation flow (INSTALL flag from the parent). Required by installFinish.

auth

get auth(): AuthManager

Authorization manager. Exposes getAuthData, refreshAuth, getUniq, isAdmin, plus auto-refresh on 401 responses.

parent

get parent(): ParentManager

Parent window manager. Posting messages to and reading metadata from the surrounding Bitrix24 page.

slider

get slider(): SliderManager

Slider manager. Open / close Bitrix24 sliders.

placement

get placement(): PlacementManager

Placement manager. Inspect and update the placement context.

options

get options(): OptionsManager

Options manager. Read application / user options synced from the parent window.

dialog

get dialog(): DialogManager

Dialog manager. Ask Bitrix24 to render its native confirm / message / file pickers.

Methods

init

init(): Promise<void>

Performs the parent-window handshake (getInitData), wires the manager state, and creates both REST API HTTP clients. Idempotent in practice — initializeB24Frame() deduplicates concurrent calls.

destroy

destroy(): void

Tears the frame down: unsubscribes from postMessage events, clears the pending-command timers, and drops the placement callbacks. Always call before unmounting the host component to avoid leaks.

Any command still waiting on the parent window is rejected with JSSDK_FRAME_DISPOSED rather than left pending — nothing can answer it once the listener is gone, and silence is the one outcome a caller cannot act on. Mirrors how a disposed PullClient rejects start() with PULL_DISPOSED.

This matters for a command whose promise you discarded. parent.closeApplication() and slider.closeSliderAppPage() are the usual pair, since they run precisely while the app is closing: if you call one without awaiting it and destroy the frame in the same breath, attach .catch(() => {}) so the rejection does not surface as an unhandled one.

installFinish

installFinish(): Promise<any>

Sends setInstallFinish to the parent. The returned promise rejects with an SdkError whose code is JSSDK_FRAME_INSTALL_ALREADY_FINISHED (message: Application was previously installed. You cannot call installFinish) when called outside install mode — guard with isInstallMode.

An application with an installation interface that never calls this stays half-installed, and the portal does not deliver events to it. Handlers bound with event.bind never fire, placements bound with placement.bind never appear, and other outgoing calls never reach your endpoints — even though each of those registration calls returned success.This is Bitrix24's documented behaviour: What doesn't work until installation is complete lists exactly placement.bind and event.bind as inert until the install is finished. (That page is the authority here; the SDK cannot reproduce portal-side behaviour, so if what you see differs — for instance on a self-hosted portal — trust the app.info check below over this prose.)Nothing fails loudly. Registration succeeds, imbot.register returns a botId, querying the handlers lists them — and no traffic ever arrives. Every visible signal says the setup is correct, which is why this is usually debugged at the wrong layer: nginx, tunnels, TLS, routing.Call it once, from the install page, as the last step of your install flow.This applies only to an app that has an installation interface. An API-only app with no interface must not call installFinish() — its installation completes automatically, and the method works only inside a browser interface frame (an install callback runs server-side and cannot call it). So if an app with no UI is missing events, installFinish() is not the cause; look elsewhere.Finishing the installation is a lifecycle step, not a security one. An app that also runs an OAuth install/uninstall endpoint still has to verify application_token on ONAPPINSTALL / ONAPPUNINSTALL — see Security patterns. The two are unrelated, and doing this one does not cover the other.To check an application after the fact, ask the portal:
const response = await $b24.actions.v2.call.make<{ INSTALLED: boolean }>({
  method: 'app.info',
  requestId: 'app-info-1'
})
console.log(response.getData()!.result.INSTALLED) // false ⇒ installFinish() never landed
The portal reacts to this call by reloading the page: from the installer it restarts the application, from the settings stage it re-runs the init handlers.That is stronger than "the next line might not run". This command is sent without the SDK's isSafely timer, so its promise settles only when the parent window answers — and if the reload happens first, the promise never settles at all. The await does not return, and a finally block attached to it does not execute. Treat installFinish() as the last statement of the install flow, and do not build state that depends on it resolving.

getAppSid

getAppSid(): string

Application session id relative to the parent window (mirrors APP_SID).

getLang

getLang(): B24LangList

Bitrix24 interface language enum. See LangList.

getTargetOrigin / getTargetOriginWithPath

getTargetOrigin(): string
getTargetOriginWithPath(): Map<ApiVersion, string>

Portal origin and per-version REST endpoints (parent-supplied).

Inherited from AbstractB24

getHttpClient, setHttpClient, setRestrictionManagerParams, getLogger, setLogger, actions, tools. See:

Usage

import {
  initializeB24Frame,
  LoggerFactory,
  EnumCrmEntityTypeId,
  Text,
  type B24Frame,
  type ISODate
} from '@bitrix24/b24jssdk'

const $logger = LoggerFactory.createForBrowser('MyApp', import.meta.env?.DEV === true)
let $b24: undefined | B24Frame

async function loadCompanies() {
  if (!$b24) return

  const response = await $b24.actions.v2.callList.make<{ id: number, title: string, createdTime: ISODate }>({
    method: 'crm.item.list',
    params: {
      entityTypeId: EnumCrmEntityTypeId.company,
      select: ['id', 'title', 'createdTime']
    },
    idKey: 'id',
    requestId: 'companies-list'
  })

  if (!response.isSuccess) {
    $logger.error('REST error', { messages: response.getErrorMessages() })
    return
  }

  return response.getData()!.map((item) => ({
    id: Number(item.id),
    title: item.title,
    createdTime: Text.toDateTime(item.createdTime)
  }))
}

async function bootstrap() {
  try {
    $b24 = await initializeB24Frame()
    const companies = await loadCompanies()
    $logger.notice('companies', { companies })
  } catch (error) {
    $logger.error('init failed', { error })
  }
}

bootstrap()
The page must run as a Bitrix24 application (inside a placement iframe). Outside that context the parent-window handshake never resolves.