Kommo + Klipfolio: KPI-дашборд продаж из данных CRM
Klipfolio - SaaS-платформа для бизнес-дашбордов, популярная у SMB-команд как альтернатива Tableau и Power BI. Klipfolio поддерживает Push API: вы отправляете данные сами, платформа хранит и визуализирует. Нативной интеграции с Kommo нет - строим ETL-скрипт на Python с hourly обновлением.
Архитектура: Push datasource
Klipfolio работает двумя способами: Pull (Klipfolio сам забирает данные по расписанию) и Push (вы отправляете данные через API). Для Kommo используем Push - у Kommo нет публичного URL который Klipfolio мог бы опросить без авторизации.
Схема:
- Cron каждый час -> Python скрипт
- Скрипт забирает данные из Kommo API
- Трансформирует в нужный формат
- Отправляет в Klipfolio Push datasource
Аутентификация Klipfolio
Klipfolio API использует API Key в заголовке apikey:
import requests
KLIPFOLIO_API_KEY = "your_klipfolio_api_key"
kf_session = requests.Session()
kf_session.headers.update({
"apikey": KLIPFOLIO_API_KEY,
"Content-Type": "application/json",
})
KF_BASE = "https://app.klipfolio.com/api/1.0"
API Key доступен в Klipfolio Account -> Profile -> API Keys.
Создание Push datasource
Создаётся один раз. Datasource ID используется при каждой отправке данных.
def create_push_datasource(name: str, columns: list) -> str:
"""Create Klipfolio push datasource. Returns datasource ID."""
payload = {
"data": {
"name": name,
"type": "push",
"data_format": "json",
}
}
r = kf_session.post(f"{KF_BASE}/datasources", json=payload)
r.raise_for_status()
return r.json()["payload"]["id"]
# Пример: datasource для ежедневной воронки
DATASOURCE_ID = create_push_datasource(
name="Kommo Daily Pipeline",
columns=["date", "stage_name", "deals_count", "total_value", "avg_deal_value"],
)
print(f"Datasource ID: {DATASOURCE_ID}") # сохранить в конфиг
Извлечение данных из Kommo
from datetime import datetime, timedelta
KOMMO_BASE = "https://YOUR.kommo.com/api/v4"
KOMMO_TOKEN = "your_bearer_token"
kommo_session = requests.Session()
kommo_session.headers.update({"Authorization": f"Bearer {KOMMO_TOKEN}"})
def get_pipeline_snapshot() -> list:
"""Get current deals by stage from Kommo."""
r = kommo_session.get(
f"{KOMMO_BASE}/leads",
params={"limit": 250, "page": 1},
)
r.raise_for_status()
deals = r.json().get("_embedded", {}).get("leads", [])
# Сгруппировать по статусам
stage_data = {}
for deal in deals:
stage_id = deal.get("status_id")
stage_name = get_stage_name(stage_id) # кэшировать из /pipelines
value = deal.get("price", 0)
if stage_name not in stage_data:
stage_data[stage_name] = {"count": 0, "total_value": 0}
stage_data[stage_name]["count"] += 1
stage_data[stage_name]["total_value"] += value
today = datetime.now().strftime("%Y-%m-%d")
rows = []
for stage_name, data in stage_data.items():
count = data["count"]
total = data["total_value"]
rows.append({
"date": today,
"stage_name": stage_name,
"deals_count": count,
"total_value": total,
"avg_deal_value": round(total / count, 2) if count else 0,
})
return rows
Отправка данных в Klipfolio Push
def push_to_klipfolio(datasource_id: str, rows: list) -> bool:
"""Push data rows to Klipfolio datasource."""
if not rows:
return False
# Klipfolio Push API принимает JSON array строк или JSON array объектов
payload = {"data": rows}
r = kf_session.post(
f"{KF_BASE}/datasources/{datasource_id}/data",
json=payload,
)
if r.status_code not in (200, 201, 204):
print(f"Klipfolio push failed: {r.status_code} {r.text}")
return False
return True
# Основной ETL
def run_etl():
print(f"ETL started at {datetime.now().isoformat()}")
rows = get_pipeline_snapshot()
success = push_to_klipfolio(DATASOURCE_ID, rows)
print(f"Pushed {len(rows)} rows: {'OK' if success else 'FAILED'}")
if __name__ == "__main__":
run_etl()
Запускается через cron: 0 * * * * python /path/to/kommo_klipfolio_etl.py
Расширенные метрики: конверсия между стадиями
def get_conversion_metrics(days: int = 30) -> list:
"""Get conversion rates between stages for last N days."""
since = int((datetime.now() - timedelta(days=days)).timestamp())
# Won deals за период
r_won = kommo_session.get(
f"{KOMMO_BASE}/leads",
params={"filter[closed_at][from]": since, "filter[statuses][0]": 142}, # 142 = Won
)
won_count = len(r_won.json().get("_embedded", {}).get("leads", []))
# Все сделки созданные за период
r_total = kommo_session.get(
f"{KOMMO_BASE}/leads",
params={"filter[created_at][from]": since},
)
total_count = len(r_total.json().get("_embedded", {}).get("leads", []))
conversion = round(won_count / total_count * 100, 1) if total_count else 0
return [{
"date": datetime.now().strftime("%Y-%m-%d"),
"period_days": days,
"total_deals": total_count,
"won_deals": won_count,
"conversion_rate": conversion,
}]
Отправляется в отдельный datasource Kommo Conversion.
Форматирование дат для Klipfolio
Важная деталь: Klipfolio строго интерпретирует формат даты. Принимаемые форматы:
YYYY-MM-DD- безопасный формат для датYYYY-MM-DD HH:MM:SS- для timestamp- Unix timestamp (integer) - тоже работает
Числа передавайте как числа (не строки): "total_value": 45000, не "total_value": "45000". Klipfolio применяет числовые функции агрегации только к числовым полям.
Реальный кейс
SaaS-компания с командой продаж 5 человек использовала ручной экспорт из Kommo раз в неделю в Google Sheets, затем строила графики вручную. Руководитель получал статус pipeline с задержкой 3-7 дней.
После ETL Kommo -> Klipfolio:
- Дашборд обновляется каждый час
- TV-экран в офисе показывает текущий pipeline value и conversion rate
- Руководитель видит картину в реальном времени без запроса к команде
Настройка ETL заняла 2 рабочих дня, включая дизайн дашборда в Klipfolio.
Для кого подходит
Команды продаж 3-15 человек, которым нужен простой живой дашборд без сложной BI-инфраструктуры. Klipfolio дешевле и проще чем Tableau, но мощнее чем Google Data Studio для Klip-based визуализации.
Для более мощных BI-решений - Kommo + Metabase (self-hosted, SQL), Kommo + Tableau (enterprise), Kommo + Grafana (open-source).
Часто задаваемые вопросы
Чем Klipfolio отличается от Tableau или Power BI?
Klipfolio проще в настройке и дешевле ($99-299/мес против $70+/user). Визуализации называются “Klips” - каждый Klip подключается к отдельному datasource. Нет SQL-редактора как в Metabase. Оптимален для предустановленных KPI-метрик, не для ad-hoc анализа.
Как обновить исторические данные в datasource?
Klipfolio Push API по умолчанию заменяет данные при каждой отправке (replace mode). Для append (добавления строк) используйте "mode": "append" в параметрах POST-запроса. Для хранения истории рекомендуется append с полем date - так Klipfolio показывает тренды.
Сколько datasources можно создать?
Зависит от тарифного плана. На стартовом плане - до 20 datasources. Для Kommo-интеграции обычно достаточно 3-5: воронка по стадиям, конверсия, среднее время в сделке, выручка по менеджерам.
Есть ли готовые шаблоны Klip для CRM-данных?
Klipfolio Gallery содержит готовые Klip-шаблоны для sales-метрик. При создании нового Klip выберите Gallery -> Sales -> “Sales Pipeline” или “Conversion Funnel” и подключите к вашему datasource. Настройка полей занимает 15-20 минут.
Итог
ETL Kommo -> Klipfolio - самое простое BI-решение для малых команд продаж:
- Klipfolio API Key в заголовке
apikey - Push datasource: создаётся один раз, обновляется каждый час
- Данные отправляются как JSON array объектов
- Числа как числа, даты в формате
YYYY-MM-DD- иначе агрегация не работает
Если команда продаж нужен живой дашборд и нет ресурсов на BI-инфраструктуру - обратитесь к Exceltic.dev. Настроим ETL и дашборд под ваши метрики.