Kommo + Sisense: BI-аналитика продаж из CRM-данных в реальном времени
При интеграции Kommo и Sisense данные сделок, контактов и активностей автоматически попадают в хранилище Sisense через scheduled sync. Руководитель видит актуальные дашборды - конверсия по этапам, средний чек, velocity сделок - без ручного экспорта из Kommo.
Sisense - enterprise BI-платформа с собственным столбчатым хранилищем ElastiCube, которое позволяет работать с большими объёмами данных без традиционного ETL. Популярна среди компаний, которым нужны встроенные (embedded) аналитические дашборды внутри собственных продуктов или глубокая кастомизация визуализаций.
Для компаний, у которых основная воронка продаж живёт в Kommo, Sisense решает ключевую проблему: стандартные отчёты Kommo дают агрегированные цифры, но не позволяют делать сложные срезы - по менеджеру + источнику + периоду + размеру сделки одновременно. Это требует выгрузки в BI.
В проектах по кастомным интеграциям Kommo мы видим устойчивый паттерн: руководство хочет видеть pipeline-данные в корпоративной BI-системе, но нативного коннектора между Kommo и Sisense нет. Данные экспортируются вручную через CSV раз в неделю, аналитик тратит часы на сводные таблицы, а к моменту отправки отчёт уже устарел. Задержка между событием в воронке и его отражением в дашборде - от нескольких дней до недели. В этой статье разберём архитектуру ETL-решения, которое закрывает этот разрыв: scheduled sync из Kommo API через промежуточное хранилище до Sisense ElastiCube.
Почему нативная интеграция не работает
Sisense не имеет готового коннектора для Kommo. Коннекторы для CRM в Sisense есть для Salesforce и HubSpot - но не для Kommo. Это означает, что стандартный путь (настроить data source в Sisense и нажать «Connect») не работает.
Alternative - ручной экспорт CSV из Kommo и загрузка в Sisense - имеет очевидные ограничения: данные устаревают, процесс требует регулярных ручных действий, объёмные выгрузки из Kommo ограничены пагинацией и лимитами API.
Запрос через Zapier здесь бессмысленен: Sisense - это аналитическое хранилище, а не операционный инструмент. Zapier не умеет инкрементально обновлять ElastiCube-датасеты.
Что реализовывается - архитектура решения
Kommo API (scheduled)
|
| Каждые N часов:
| - выгрузить новые/изменённые сделки
| - выгрузить активности (notes, calls, emails)
| - выгрузить контакты и компании
v
ETL-сервис (Python)
|
| Трансформация:
| - нормализация статусов
| - расчёт derived metrics (days_in_stage, deal_velocity)
| - enrichment из кастомных полей
v
Промежуточное хранилище (PostgreSQL / BigQuery)
|
v
Sisense ElastiCube (scheduled build)
|
v
Sisense Dашборды:
- Pipeline overview
- Manager performance
- Stage conversion
- Revenue forecast
Ключевое архитектурное решение - промежуточное хранилище. Прямая загрузка из API в Sisense каждый раз пересоздаёт весь датасет. Промежуточная БД хранит накопленную историю и позволяет делать инкрементальные обновления (только новые и изменённые записи).
Технические детали
Kommo API v4 использует Long-lived access token или OAuth 2.0. Для scheduled sync рекомендуется Long-lived token с правами leads, contacts, companies, notes, calls. API возвращает данные постранично (по 250 записей), для полной выгрузки нужна рекурсивная пагинация по параметру page.
Sisense поддерживает несколько способов загрузки данных в ElastiCube: JDBC-коннектор (подключение к PostgreSQL/BigQuery), Sisense REST API для управления builds и CSV-коннектор. Для production рекомендуется JDBC-подключение к промежуточной БД.
import requests
import psycopg2
from datetime import datetime, timedelta
import json
KOMMO_BASE_URL = "https://YOUR_ACCOUNT.kommo.com/api/v4"
KOMMO_TOKEN = "your_long_lived_token"
def fetch_modified_leads(since_timestamp: int) -> list:
"""Выгружает сделки, изменённые с заданного времени"""
headers = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
leads = []
page = 1
while True:
resp = requests.get(
f"{KOMMO_BASE_URL}/leads",
headers=headers,
params={
"filter[updated_at][from]": since_timestamp,
"page": page,
"limit": 250,
"with": "contacts,companies,loss_reason,pipeline"
}
)
if resp.status_code == 204: # Нет данных
break
resp.raise_for_status()
data = resp.json()
batch = data.get("_embedded", {}).get("leads", [])
if not batch:
break
leads.extend(batch)
# Проверка пагинации
next_link = data.get("_links", {}).get("next")
if not next_link:
break
page += 1
return leads
def transform_lead(lead: dict) -> dict:
"""Трансформирует сырые данные Kommo в плоскую запись для BI"""
created_at = datetime.fromtimestamp(lead["created_at"])
updated_at = datetime.fromtimestamp(lead["updated_at"])
# Расчёт производных метрик
close_date = datetime.fromtimestamp(lead["closed_at"]) if lead.get("closed_at") else None
days_to_close = (close_date - created_at).days if close_date else None
return {
"lead_id": lead["id"],
"name": lead["name"],
"price": lead.get("price", 0),
"status_id": lead["status_id"],
"pipeline_id": lead["pipeline_id"],
"responsible_user_id": lead["responsible_user_id"],
"created_at": created_at.isoformat(),
"updated_at": updated_at.isoformat(),
"closed_at": close_date.isoformat() if close_date else None,
"days_to_close": days_to_close,
"is_won": lead.get("status_id") == 142, # WON status
"is_lost": lead.get("status_id") == 143, # LOST status
"loss_reason": lead.get("loss_reason", {}).get("name") if lead.get("loss_reason") else None,
# Кастомные поля
"deal_type": get_custom_field(lead, "deal_type"),
"lead_source": get_custom_field(lead, "lead_source"),
"industry": get_custom_field(lead, "industry"),
"company_size": get_custom_field(lead, "company_size")
}
def get_custom_field(lead: dict, field_name: str) -> str:
for field in lead.get("custom_fields_values", []) or []:
if field.get("field_code") == field_name:
values = field.get("values", [])
return values[0]["value"] if values else None
return None
def sync_to_postgres(leads: list, conn):
"""Записывает/обновляет сделки в промежуточной БД (upsert)"""
cursor = conn.cursor()
for lead in leads:
cursor.execute("""
INSERT INTO kommo_leads (
lead_id, name, price, status_id, pipeline_id,
responsible_user_id, created_at, updated_at, closed_at,
days_to_close, is_won, is_lost, loss_reason,
deal_type, lead_source, industry, company_size
) VALUES (
%(lead_id)s, %(name)s, %(price)s, %(status_id)s, %(pipeline_id)s,
%(responsible_user_id)s, %(created_at)s, %(updated_at)s, %(closed_at)s,
%(days_to_close)s, %(is_won)s, %(is_lost)s, %(loss_reason)s,
%(deal_type)s, %(lead_source)s, %(industry)s, %(company_size)s
)
ON CONFLICT (lead_id) DO UPDATE SET
price = EXCLUDED.price,
status_id = EXCLUDED.status_id,
updated_at = EXCLUDED.updated_at,
closed_at = EXCLUDED.closed_at,
days_to_close = EXCLUDED.days_to_close,
is_won = EXCLUDED.is_won,
is_lost = EXCLUDED.is_lost
""", transform_lead(lead))
conn.commit()
Пошаговая реализация
Шаг 1. Спроектируйте схему данных под ваши BI-задачи
Определите, какие метрики нужны на дашборде: конверсия по этапам, средний чек по менеджеру, velocity по источнику лида. Под эти вопросы спроектируйте таблицы в промежуточной БД. Стандартные таблицы: kommo_leads, kommo_contacts, kommo_companies, kommo_activities, kommo_pipelines, kommo_users.
Шаг 2. Разверните ETL-сервис
Настройте cron-задачу для запуска ETL каждые 4-6 часов. При каждом запуске: читаем last_sync_timestamp из служебной таблицы, выгружаем только изменённые записи через filter[updated_at][from], трансформируем и upsert в PostgreSQL, обновляем last_sync_timestamp.
Шаг 3. Подключите Sisense к промежуточной БД
В Sisense Admin -> Data -> Add New Data Source выберите PostgreSQL. Укажите connection string. Создайте ElastiCube, добавьте таблицы из промежуточной БД. Настройте relationship между таблицами (leads -> users, leads -> pipelines).
Шаг 4. Создайте scheduled build в Sisense
Настройте автоматическую пересборку ElastiCube каждые 6-8 часов. Sisense забирает свежие данные из PostgreSQL и обновляет аналитические таблицы внутреннего хранилища.
Шаг 5. Постройте дашборды
Стандартный набор дашбордов для Kommo-данных: Pipeline overview (объём и конверсия по этапам), Manager performance (сделки, средний чек, win rate по менеджеру), Lead source analysis (откуда приходят лучшие лиды), Deal velocity (средний цикл сделки по типам).
Реальный кейс с цифрами
B2B SaaS-компания, 20 человек, годовой ARR в районе $1-2M. Команда продаж 5 человек работает в Kommo, CEO и инвесторы хотят видеть pipeline data в реальном времени.
До интеграции: аналитик раз в неделю экспортировал CSV из Kommo, делал сводные таблицы в Excel и рассылал по почте. Данные устаревали сразу после отправки. На подготовку отчёта уходило 3-4 часа в неделю.
Отдельная проблема: при вопросе «почему упала конверсия на этапе Demo?» у команды не было инструмента для быстрого разреза - нужно было снова выгружать CSV и строить pivot вручную.
После интеграции Kommo + Sisense через Exceltic.dev:
- CEO открывает дашборд в браузере и видит актуальные данные с задержкой 4-6 часов
- Время на подготовку еженедельного отчёта: 0 (автоматически)
- Ad-hoc анализ («покажи конверсию за последние 30 дней только по лидам из LinkedIn»): 2-3 минуты в Sisense вместо 2-3 часов в Excel
Об остальных функциях Kommo CRM для аналитики продаж - в обзорной статье.
Для кого подходит
Интеграция Kommo + Sisense актуальна для:
- Компаний с Sisense как корпоративным стандартом BI, которым нужно добавить CRM-данные в существующую платформу
- B2B с 5+ менеджерами по продажам, где нужна аналитика производительности команды
- Компаний с отчётностью перед бордом или инвесторами - Sisense позволяет создать красивые презентационные дашборды
- SaaS с embedded analytics - данные из Kommo можно встроить в клиентский интерфейс вашего продукта
Если у вас нет корпоративной лицензии Sisense - для задач аналитики Kommo-данных рассмотрите более доступные варианты: Metabase (self-hosted, бесплатно), Looker Studio (бесплатно), Power BI.
Часто задаваемые вопросы
Sisense поддерживает PostgreSQL как источник данных?
Да. Sisense поддерживает PostgreSQL через JDBC-коннектор из коробки. Это один из наиболее распространённых источников данных для Sisense ElastiCube. Также поддерживаются MySQL, SQL Server, BigQuery, Redshift и другие OLAP-хранилища.
С какой задержкой данные попадают из Kommo в Sisense?
Задержка определяется частотой запуска ETL-сервиса и расписанием rebuild ElastiCube в Sisense. Типовая конфигурация: ETL каждые 4 часа + rebuild ElastiCube каждые 4 часа со сдвигом = данные обновляются каждые 4-8 часов. Для real-time аналитики можно сократить интервал до 1 часа, но это увеличивает нагрузку на Kommo API.
Как обеспечить историчность данных при изменении стадии сделки?
Kommo не хранит историю изменений этапов в стандартном API (только текущий статус). Для SCD (Slowly Changing Dimensions) нужно либо использовать Kommo events/activities API для восстановления истории, либо фиксировать каждое изменение статуса при каждом ETL-прогоне. Второй подход проще: при каждом sync создаём snapshot-запись с текущим status_id и временем фиксации.
Можно ли использовать другую BI-платформу вместо Sisense?
Да. Архитектура с промежуточной PostgreSQL-БД универсальна. Sisense можно заменить на Tableau, Power BI, Looker или Metabase - они все поддерживают PostgreSQL как источник. Сам ETL-сервис остаётся неизменным, меняется только последний шаг подключения. О других вариантах аналитики для Kommo CRM - в нашем обзоре.
Сколько времени занимает разработка интеграции Kommo + Sisense?
Базовый ETL (выгрузка сделок + контактов + активностей в PostgreSQL) + подключение к Sisense + 2-3 стандартных дашборда - 4-5 недель. Включая настройку промежуточной БД, ETL-сервиса с обработкой ошибок и пагинацией. Embedded analytics или дополнительные источники данных - оцениваем отдельно.
Если вам нужна BI-аналитика по данным Kommo в Sisense - опишите задачу команде Exceltic.dev. Разберём архитектуру хранилища и оценим объём работ.