Как встроить виджет во вкладку карточки CRM
Scope:
placement,crmКто может выполнять методы:
placement.bind— администраторcrm.item.get— любой пользователь с правом чтения сделки
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
Вкладка в карточке CRM позволяет показать интерфейс приложения рядом с основными данными элемента. В этом сценарии добавим вкладку в карточку сделки, получим идентификатор открытой сделки и запросим ее данные.
Для сценария последовательно выполним методы:
- placement.bind — зарегистрируем обработчик для вкладки
CRM_DEAL_DETAIL_TAB - crm.item.get — получим данные сделки по идентификатору из
PLACEMENT_OPTIONS
Исходный пример и дополнительные материалы доступны в уроке Встройка в карточку CRM.
Как работает сценарий
Приложение регистрирует URL обработчика методом placement.bind и указывает код CRM_DEAL_DETAIL_TAB. После завершения установки приложения в карточке сделки появляется новая вкладка.
Когда пользователь открывает вкладку, Битрикс24 загружает обработчик в iframe и передает ему контекст вызова. В PLACEMENT_OPTIONS.ID приходит идентификатор текущей сделки. Обработчик передает этот идентификатор в crm.item.get и показывает полученные данные.
1. Подготовьте приложение
Создайте приложение с интерфейсом и добавьте ему права:
placement— для регистрации обработчика виджетаcrm— для получения данных сделки
Код регистрации и обработчик вкладки можно разместить в отдельных файлах или объединить в одном файле с разными ветками выполнения.
Разместите страницу обработчика по публичному HTTPS-адресу. В примерах используется адрес:
https://your-domain.example/deal-tab.php
Сервер должен разрешать открытие страницы в iframe. Проверьте заголовок X-Frame-Options и директиву frame-ancestors заголовка Content-Security-Policy: они не должны запрещать встраивание страницы в Битрикс24.
URL обработчика должен быть доступен из внешней сети. Не используйте localhost, адреса локальной сети и самоподписанные SSL-сертификаты.
Метод placement.bind работает только в контексте приложения. Входящий вебхук для регистрации вкладки не подходит.
2. Зарегистрируйте вкладку
Зарегистрируем обработчик методом placement.bind. Передадим параметры:
PLACEMENT— код места встраиванияCRM_DEAL_DETAIL_TABHANDLER— публичный URL страницы, которая откроется во вкладкеTITLE— название вкладкиLANG_ALL— локализованные названия вкладки
Как использовать примеры в документации
// npm install @bitrix24/b24jssdk
// Страница настроек приложения, открытая в iframe Битрикс24
import { initializeB24Frame } from '@bitrix24/b24jssdk'
const $b24 = await initializeB24Frame()
const response = await $b24.actions.v2.call.make({
method: 'placement.bind',
params: {
PLACEMENT: 'CRM_DEAL_DETAIL_TAB',
HANDLER: 'https://your-domain.example/deal-tab.php',
TITLE: 'Deal data',
LANG_ALL: {
ru: {
TITLE: 'Данные сделки',
},
en: {
TITLE: 'Deal data',
},
},
},
requestId: 'placement-bind',
})
if (!response.isSuccess) {
throw new Error(response.getErrorMessages().join('; '))
}
console.info('Вкладка зарегистрирована')
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Core\Exceptions\BaseException;
// $b24 построен на токене приложения — см. сценарий
// «Как встроить виджет в лид в виде пользовательского поля»
try
{
$b24->getPlacementScope()->placement()->bind(
'CRM_DEAL_DETAIL_TAB',
'https://your-domain.example/deal-tab.php',
[
'ru' => ['TITLE' => 'Данные сделки'],
'en' => ['TITLE' => 'Deal data'],
]
);
echo 'Вкладка зарегистрирована';
}
catch (BaseException $exception)
{
echo $exception->getMessage();
}
# pip install b24pysdk
# client построен на токене приложения — см. сценарий
# «Как встроить виджет в лид в виде пользовательского поля»
from b24pysdk.errors import BitrixAPIError
try:
bitrix_response = client.placement.bind(
placement="CRM_DEAL_DETAIL_TAB",
handler="https://your-domain.example/deal-tab.php",
title="Deal data",
lang_all={
"ru": {"TITLE": "Данные сделки"},
"en": {"TITLE": "Deal data"},
},
).response
print("Вкладка зарегистрирована:", bitrix_response.result)
except BitrixAPIError as error:
print(error)
Если обработчик успешно зарегистрирован, метод вернет true.
{
"result": true
}
После регистрации завершите установку приложения. Пока установка не завершена, вкладка недоступна обычным пользователям.
3. Обработайте открытие вкладки
При открытии вкладки Битрикс24 передает обработчику данные POST-запросом. Для карточки сделки основные параметры выглядят так:
PLACEMENT=CRM_DEAL_DETAIL_TAB
PLACEMENT_OPTIONS={"ID":"3473"}
PLACEMENT_OPTIONS передается как JSON-строка. В PHP и Python преобразуйте ее в массив или словарь — например, функцией json_decode или json.loads. В B24JsSDK свойство $b24.placement.options возвращает готовый объект, а $b24.placement.placement — код места встраивания.
|
Параметр |
Описание |
|
PLACEMENT |
Код места встраивания. Для вкладки сделки приходит |
|
PLACEMENT_OPTIONS |
JSON-строка с контекстом открытой карточки |
|
ID |
Идентификатор сделки внутри |
|
DOMAIN |
Адрес Битрикс24, в котором пользователь открыл вкладку |
|
PROTOCOL |
Протокол для обращения к Битрикс24: |
|
AUTH_ID |
OAuth-токен пользователя, который открыл вкладку. PHP-обработчик использует токен для вызова |
Полный набор служебных параметров запроса описан на странице вкладки в карточке CRM.
4. Получите данные сделки
Вызовем crm.item.get из обработчика. Для сделки передадим:
entityTypeId: 2— идентификатор типа объекта CRM «Сделка»id— идентификатор изPLACEMENT_OPTIONS.ID
Метод выполняется с авторизацией пользователя, который открыл вкладку:
- JS работает внутри iframe —
initializeB24Frameберет авторизацию из контекста вкладки - PHP и Python строят клиент на данных запроса, которые Битрикс24 передает обработчику, включая токен
AUTH_ID
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Данные сделки</title>
</head>
<body>
<h2 id="deal-title">Загрузка данных сделки</h2>
<div id="deal-stage"></div>
<script type="module">
// npm install @bitrix24/b24jssdk
import { initializeB24Frame } from '@bitrix24/b24jssdk'
const $b24 = await initializeB24Frame()
const dealId = Number($b24.placement.options.ID)
if (
$b24.placement.placement !== 'CRM_DEAL_DETAIL_TAB'
|| !Number.isInteger(dealId)
|| dealId <= 0
) {
document.getElementById('deal-title').textContent =
'Не удалось определить сделку'
} else {
const response = await $b24.actions.v2.call.make({
method: 'crm.item.get',
params: {
entityTypeId: 2,
id: dealId,
},
requestId: 'deal-get',
})
if (!response.isSuccess) {
document.getElementById('deal-title').textContent =
response.getErrorMessages().join('; ')
} else {
const deal = response.getData().result.item
document.getElementById('deal-title').textContent =
deal.title || 'Сделка без названия'
document.getElementById('deal-stage').textContent =
'Стадия: ' + deal.stageId
}
}
</script>
</body>
</html>
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Core\Credentials\ApplicationProfile;
use Bitrix24\SDK\Core\Exceptions\BaseException;
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
$placement = (string)$request->request->get('PLACEMENT', '');
$placementOptions = json_decode(
(string)$request->request->get('PLACEMENT_OPTIONS', '[]'),
true
) ?: [];
$dealId = (int)($placementOptions['ID'] ?? 0);
$error = '';
$deal = null;
if ($placement !== 'CRM_DEAL_DETAIL_TAB' || $dealId <= 0)
{
$error = 'Не удалось получить контекст вызова';
}
else
{
$appProfile = ApplicationProfile::initFromArray([
'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'local.xxxxxxxx.xxxxxxxx',
'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'yyyyyyyy',
'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'crm,placement',
]);
try
{
// SDK сам возьмет DOMAIN и AUTH_ID из запроса встройки
$b24 = ServiceBuilderFactory::createServiceBuilderFromPlacementRequest(
$request,
$appProfile
);
$deal = $b24->getCRMScope()->item()->get(2, $dealId)->item();
}
catch (BaseException $exception)
{
$error = $exception->getMessage();
}
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Данные сделки</title>
</head>
<body>
<?php if ($error !== ''): ?>
<p><?=htmlspecialchars($error)?></p>
<?php else: ?>
<h2><?=htmlspecialchars($deal->title ?? 'Сделка без названия')?></h2>
<p>Стадия: <?=htmlspecialchars($deal->stageId ?? '')?></p>
<?php endif; ?>
</body>
</html>
# pip install b24pysdk flask
from flask import Flask, request
from b24pysdk import BitrixApp, BitrixToken, Client
from b24pysdk.errors import BitrixAPIError
import json
app = Flask(__name__)
bitrix_app = BitrixApp(
client_id="local.xxxxxxxx.xxxxxxxx",
client_secret="yyyyyyyy",
)
@app.post("/deal-tab")
def deal_tab():
placement = request.form.get("PLACEMENT", "")
options = json.loads(request.form.get("PLACEMENT_OPTIONS", "{}") or "{}")
deal_id = int(options.get("ID", 0))
if placement != "CRM_DEAL_DETAIL_TAB" or deal_id <= 0:
return "Не удалось получить контекст вызова"
# Битрикс24 передает обработчику домен и токен пользователя
client = Client(
BitrixToken(
domain=request.args.get("DOMAIN", ""),
auth_token=request.form.get("AUTH_ID", ""),
bitrix_app=bitrix_app,
)
)
try:
deal = client.crm.item.get(
entity_type_id=2,
bitrix_id=deal_id,
).response.result["item"]
except BitrixAPIError as error:
return str(error)
return f"{deal.get('title', 'Сделка без названия')} — стадия: {deal.get('stageId', '')}"
Метод вернет объект item с данными сделки, доступными пользователю, чья авторизация используется в запросе.
{
"result": {
"item": {
"id": 3473,
"title": "Подготовка предложения",
"stageId": "NEW"
}
}
}
Идентификатор из PLACEMENT_OPTIONS можно использовать и для других действий: получить связанные контакты и компанию, запросить данные во внешней системе или показать собственный интерфейс работы со сделкой.
5. Проверьте виджет
- Установите приложение в тестовый Битрикс24
- Убедитесь, что установка приложения завершена
- Откройте раздел CRM
- Откройте любую сделку
- Найдите вкладку Данные сделки
- Проверьте, что обработчик показывает название и стадию открытой сделки
Если вкладка не появилась, проверьте регистрацию обработчика методом placement.get. В ответе должны быть код CRM_DEAL_DETAIL_TAB и URL страницы обработчика.
Другие карточки CRM
По тому же сценарию можно добавить вкладку в карточки других объектов. Замените код в PLACEMENT и укажите соответствующий entityTypeId в crm.item.get.
|
Объект CRM |
PLACEMENT |
entityTypeId |
|
Лид |
|
|
|
Сделка |
|
|
|
Контакт |
|
|
|
Компания |
|
|
|
Счет |
|
|
Коды для коммерческих предложений и смарт-процессов смотрите в описании точки CRM_XXX_DETAIL_TAB.