Item in the BI Analytics Menu BI_ANALYTICS_MENU

Choose a tool for developing with an AI agent:

  • use Alaio Vibecode to build an app for Bitrix24 from a task description without knowing any programming language. The agent writes the code and deploys the app to a server, with no manual hosting setup
  • use the MCP server to develop a REST API integration in your own project. The agent refers to the official REST documentation

Scope: placement

The widget adds its own item to the BI analytics menu — next to the ready-made Bitrix24 reports and the connected Microsoft Power BI and Google Looker Studio dashboards. Clicking the item opens a separate page where Bitrix24 shows the content of the handler.

Use the placement for applications that build their own reports on Bitrix24 data: for the user they end up in the same place as the built-in analytics.

The placement code is specified in the PLACEMENT parameter of the placement.bind method.

The widget is not displayed in the interface until the application installation is complete. Check the application installation

Where the Widget is Embedded

Placement Code

Location

BI_ANALYTICS_MENU

Item in the BI analytics menu

Where to Find It in the Interface

Open the CRM Analytics section and expand the BI analytics group in the left menu of the section. The application item is added to this group last — after the built-in services and the reports that are already set up in Bitrix24.

Application item in the BI analytics menu

The item name is set by the TITLE parameter during registration. If the parameter is not passed, the application name is displayed.

Only the employees who are allowed to work with BI analytics see the item. Other users do not have it in the menu.

What the Handler Receives

The handler receives no data. This is what makes the placement different from most widgets: Bitrix24 opens the address from the HANDLER parameter in a frame with a regular GET request and passes neither authorization nor call context

Neither AUTH_ID, nor member_id, nor PLACEMENT_OPTIONS reaches the handler. The application has to determine on its own whom to show the report to: for example, by its own session or by the parameters you have put into the handler address in advance.

If the application needs authorization and the call context, use the placements of the section that call the handler with a POST request — for example CRM_ANALYTICS_MENU.

Address of the Widget Page

The item leads to a separate page of the form /biconnector/placement.php?id=<registration identifier>. The registration identifier is returned by the placement.get method in the id field.

If Bitrix24 recognizes the handler address as a public report of an external BI system, the page does not open — the report opens in a new browser tab.

OPTIONS when registering via placement.bind

The BI_ANALYTICS_MENU placement does not support the OPTIONS parameters. Bitrix24 accepts the passed values without an error but does not store them: the placement.get method returns an empty array for such a binding.

Code Examples

How to Use Examples in Documentation

curl -X POST \
          -H "Content-Type: application/json" \
          -H "Accept: application/json" \
          -d '{
            "PLACEMENT": "BI_ANALYTICS_MENU",
            "HANDLER": "https://your-domain.com/widgets/bi-report.php",
            "TITLE": "Shipment report",
            "LANG_ALL": {
              "en": {
                "TITLE": "Shipment report"
              },
              "de": {
                "TITLE": "Versandbericht"
              }
            },
            "auth": "**put_access_token_here**"
          }' \
          https://**put_your_bitrix24_address**/rest/placement.bind
        
// This snippet is an ES module: top-level await requires type="module" or a bundler.
        // $b24 is an already-initialized SDK instance (see the SDK "Get started" guide).
        import { Text } from '@bitrix24/b24jssdk'
        import type { B24Frame } from '@bitrix24/b24jssdk'
        
        declare const $b24: B24Frame
        
        try {
          const response = await $b24.actions.v2.call.make<boolean>({
            method: 'placement.bind',
            params: {
              PLACEMENT: 'BI_ANALYTICS_MENU',
              HANDLER: 'https://your-domain.com/widgets/bi-report.php',
              TITLE: 'Shipment report',
              LANG_ALL: {
                en: {
                  TITLE: 'Shipment report',
                },
                de: {
                  TITLE: 'Versandbericht',
                },
              },
            },
            requestId: Text.getUuidRfc4122()
          })
        
          // The payload is available only on a successful response
          if (!response.isSuccess) {
            console.error(response.getErrorMessages().join('; '))
          } else {
            const result = response.getData()!.result
            console.info('Placement bound successfully:', result)
          }
        } catch (error) {
          // Thrown on transport or SDK failures (AjaxError, SdkError, etc.)
          console.error(error)
        }
        
<!-- Load the SDK (UMD build); it is exposed as the global B24Js -->
        <script src="https://unpkg.com/@bitrix24/b24jssdk@1/dist/umd/index.min.js"></script>
        <script>
          async function bindBiAnalyticsMenu() {
            try {
              // Initialize the SDK inside a Bitrix24 frame
              const $b24 = await B24Js.initializeB24Frame()
        
              const response = await $b24.actions.v2.call.make({
                method: 'placement.bind',
                params: {
                  PLACEMENT: 'BI_ANALYTICS_MENU',
                  HANDLER: 'https://your-domain.com/widgets/bi-report.php',
                  TITLE: 'Shipment report',
                  LANG_ALL: {
                    en: {
                      TITLE: 'Shipment report',
                    },
                    de: {
                      TITLE: 'Versandbericht',
                    },
                  },
                },
                requestId: B24Js.Text.getUuidRfc4122()
              })
        
              // The payload is available only on a successful response
              if (!response.isSuccess) {
                console.error(response.getErrorMessages().join('; '))
                return
              }
        
              const result = response.getData().result
              console.info('Placement bound successfully:', result)
            } catch (error) {
              // Thrown on transport or SDK failures (AjaxError, SdkError, etc.)
              console.error(error)
            }
          }
        
          document.addEventListener('DOMContentLoaded', bindBiAnalyticsMenu)
        </script>
        
try {
            $response = $b24Service
                ->core
                ->call(
                    'placement.bind',
                    [
                        'PLACEMENT' => 'BI_ANALYTICS_MENU',
                        'HANDLER' => 'https://your-domain.com/widgets/bi-report.php',
                        'TITLE' => 'Shipment report',
                        'LANG_ALL' => [
                            'en' => [
                                'TITLE' => 'Shipment report',
                            ],
                            'de' => [
                                'TITLE' => 'Versandbericht',
                            ],
                        ],
                    ]
                );
        
            $result = $response->getResponseData()->getResult();
            if ($result->error()) {
                error_log($result->error());
            } else {
                echo 'Success: ' . print_r($result->data(), true);
            }
        } catch (Throwable $e) {
            error_log($e->getMessage());
            echo 'Error binding placement: ' . $e->getMessage();
        }
        
BX24.callMethod(
            'placement.bind',
            {
                PLACEMENT: 'BI_ANALYTICS_MENU',
                HANDLER: 'https://your-domain.com/widgets/bi-report.php',
                TITLE: 'Shipment report',
                LANG_ALL: {
                    en: { TITLE: 'Shipment report' },
                    de: { TITLE: 'Versandbericht' }
                }
            },
            function(result) {
                if (result.error()) {
                    console.error(result.error());
                } else {
                    console.log(result.data());
                }
            }
        );
        
require_once('crest.php');
        
        $result = CRest::call(
            'placement.bind',
            [
                'PLACEMENT' => 'BI_ANALYTICS_MENU',
                'HANDLER' => 'https://your-domain.com/widgets/bi-report.php',
                'TITLE' => 'Shipment report',
                'LANG_ALL' => [
                    'en' => [
                        'TITLE' => 'Shipment report',
                    ],
                    'de' => [
                        'TITLE' => 'Versandbericht',
                    ],
                ],
            ]
        );
        
        echo '<PRE>';
        print_r($result);
        echo '</PRE>';
        
// client and ctx are already created — see the Go SDK section
        res, err := client.Core().Call(ctx, "placement.bind", b24.Params{
        	"PLACEMENT": "BI_ANALYTICS_MENU",
        	"HANDLER":   "https://your-domain.com/widgets/bi-report.php",
        	"TITLE":     "Shipment report",
        	"LANG_ALL": b24.Params{
        		"ru": b24.Params{
        			"TITLE": "Shipment report",
        		},
        		"en": b24.Params{
        			"TITLE": "Shipment report",
        		},
        	},
        })
        if err != nil {
        	return fmt.Errorf("placement.bind: %w", err)
        }
        
        // The response arrives as json.RawMessage — unmarshal it into the response
        // shape of the placement.bind method, see "Response Handling" on its page.
        fmt.Printf("%s\n", res.Result)
        

Common Mistakes

Mistake

Solution

placement.bind returns WRONG_AUTH_TYPE with the description Application context required

Register the placement on behalf of an application. A placement cannot be bound with a webhook

placement.bind returns ERROR_PLACEMENT_NOT_FOUND

The code is specified incorrectly or the application has not been granted the placement scope. The placement is registered only with the BI_ANALYTICS_MENU code

The widget is registered but does not appear in the interface

Complete the application installation and reload the page

Not all employees see the item

The item is displayed only to those who are allowed to work with BI analytics

Other registration error codes are listed in the "Possible Error Codes" section of the placement.bind page.

Continue Learning