Required scopes depend on what the wizard does — at minimum
crm, user_brief, userfieldconfig, placement.A Bitrix24 application is "installing" between when the user accepts the install dialog and when the app calls installFinish(). During that window you can provision custom fields, register placements, seed app options — anything the app needs before it greets the user. This recipe shows the structure of such a flow.
Components Used
B24Button— start / retry / finish actions.B24Progress— visual progress bar.ProseH1/ProseP— title and status text.ProsePre— debug / log output.useConfetti— closing animation.
Flow
import { initializeB24Frame, type B24Frame } from '@bitrix24/b24jssdk'
let $b24: B24Frame
async function provision(): Promise<void> {
// Wrap related steps in a batch so they hit a single round-trip
await $b24.actions.v2.batch.make({
calls: {
addUserField: {
method: 'userfieldconfig.add',
params: {
moduleId: 'crm',
field: { ENTITY_ID: 'CRM_DEAL', FIELD_NAME: 'UF_CRM_DEAL_DEMO', USER_TYPE_ID: 'string' }
}
},
bindPlacement: {
method: 'placement.bind',
params: { PLACEMENT: 'CRM_DEAL_LIST_MENU', HANDLER: '/embedded/menu' }
}
},
options: {
isHaltOnError: true,
requestId: 'install:provision'
}
})
}
async function run() {
$b24 = await initializeB24Frame()
if (!$b24.isInstallMode) {
// Already installed — render the regular UI
return
}
await provision()
await $b24.installFinish()
// celebrate with useConfetti() ...
}
run().catch(console.error)
installFinish() throws Error('Application was previously installed. You cannot call installFinish') when the application is no longer in install mode — guard with isInstallMode.
Full Source
See bitrix24/b24sdk-examples for the complete wizard with progress UI, retry, and confetti.