Kommo + Redash: BI-дашборд продаж на собственных данных без вендор-локина

Kommo + Redash: BI-дашборд продаж на собственных данных без вендор-локина

Redash — open-source BI-инструмент с SQL-интерфейсом, поддержкой 35+ источников данных и встроенным шерингом дашбордов. В отличие от Superset (колонок и агрегаций) или Metabase, Redash заточен на прямые SQL-запросы к данным — аналитик пишет запрос, получает визуализацию, публикует дашборд. Связка с Kommo строится через ETL: данные CRM -> реляционная база -> Redash.

Redash vs Superset vs Metabase: когда выбирать Redash

Все три — open-source BI с self-hosting. Выбор зависит от аудитории и паттерна использования:

ПараметрRedashApache SupersetMetabase
Основной интерфейсSQL-редакторDrag-and-drop + SQLDrag-and-drop + SQL
Целевая аудиторияАналитики, разработчикиData engineersБизнес-пользователи
Порог входаСредний (нужен SQL)ВысокийНизкий
APIREST (query results, embeds)REST (Guest Token)REST
Self-hostingDocker, простDocker Compose, сложнееDocker, прост
ЛицензияBSDApache 2.0AGPL / Commercial

Redash выигрывает когда аналитика в команде — это SQL-запросы, а не GUI-конструктор. Для нетехнических пользователей — Metabase. Для сложной дата-инженерии — Superset. Сравнение с Apache Superset для Kommo-аналитики — в статье Kommo + Apache Superset.

Архитектура: Kommo -> Postgres -> Redash

┌──────────────┐       ┌──────────────┐       ┌──────────────┐
│  Kommo API   │──ETL─▶│  PostgreSQL  │◀─SQL──│    Redash    │
│  /api/v4/    │       │  (ваш сервер)│       │  Dashboard   │
└──────────────┘       └──────────────┘       └──────────────┘
         ▲                                           │
         │                                     (embed / share)
         │                               ┌──────────────────────┐
         │                               │  Head of Sales       │
         └───────────────────────────────│  (браузер или Slack) │

ETL-скрипт запускается по расписанию (cron или Celery beat). Альтернативы Postgres: BigQuery, ClickHouse (лучше для больших объёмов), MySQL.

ETL: выгрузка данных Kommo в Postgres

Схема таблиц:

CREATE TABLE kommo_deals (
    id BIGINT PRIMARY KEY,
    name TEXT,
    status_id INTEGER,
    stage_name TEXT,
    pipeline_id INTEGER,
    responsible_user_id INTEGER,
    responsible_name TEXT,
    price DECIMAL(15,2),
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    closed_at TIMESTAMP,
    loss_reason TEXT
);

CREATE TABLE kommo_contacts (
    id BIGINT PRIMARY KEY,
    name TEXT,
    email TEXT,
    company TEXT,
    created_at TIMESTAMP
);

CREATE TABLE kommo_deal_contacts (
    deal_id BIGINT,
    contact_id BIGINT,
    PRIMARY KEY (deal_id, contact_id)
);

ETL-скрипт (incremental load):

import requests
from datetime import datetime, timedelta
import psycopg2

KOMMO_DOMAIN = 'yourcompany'
KOMMO_TOKEN = 'your_token'
PG_DSN = 'postgresql://user:pass@localhost/analytics'

def fetch_kommo_leads(updated_since: datetime):
    params = {
        'limit': 250,
        'with': 'contacts',
        'filter[updated_at][from]': int(updated_since.timestamp())
    }
    page = 1
    while True:
        response = requests.get(
            f'https://{KOMMO_DOMAIN}.kommo.com/api/v4/leads',
            headers={'Authorization': f'Bearer {KOMMO_TOKEN}'},
            params={**params, 'page': page}
        )
        if response.status_code == 204:  # нет данных
            break
        data = response.json()
        leads = data.get('_embedded', {}).get('leads', [])
        if not leads:
            break
        yield from leads
        page += 1

def upsert_deal(conn, lead: dict):
    with conn.cursor() as cur:
        cur.execute('''
            INSERT INTO kommo_deals
                (id, name, status_id, price, created_at, updated_at, responsible_user_id)
            VALUES (%s, %s, %s, %s, to_timestamp(%s), to_timestamp(%s), %s)
            ON CONFLICT (id) DO UPDATE SET
                status_id = EXCLUDED.status_id,
                price = EXCLUDED.price,
                updated_at = EXCLUDED.updated_at
        ''', (
            lead['id'], lead['name'], lead['status_id'],
            lead.get('price', 0),
            lead['created_at'], lead['updated_at'],
            lead.get('responsible_user_id')
        ))

def run_etl():
    conn = psycopg2.connect(PG_DSN)
    updated_since = datetime.now() - timedelta(hours=1)  # incremental: за последний час
    for lead in fetch_kommo_leads(updated_since):
        upsert_deal(conn, lead)
    conn.commit()
    conn.close()

Redash: ключевые SQL-запросы для дашборда продаж

Конверсия воронки по этапам:

SELECT
    stage_name,
    COUNT(*) AS deals_count,
    SUM(price) AS pipeline_value,
    AVG(price) AS avg_deal_size,
    ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS pct_of_total
FROM kommo_deals
WHERE created_at >= NOW() - INTERVAL '30 days'
  AND status_id NOT IN (142, 143)  -- исключить Won/Lost для pipeline
GROUP BY stage_name
ORDER BY deals_count DESC;

Динамика закрытых сделок по неделям:

SELECT
    DATE_TRUNC('week', closed_at) AS week,
    responsible_name AS manager,
    COUNT(*) FILTER (WHERE status_id = 142) AS won_count,
    SUM(price) FILTER (WHERE status_id = 142) AS won_revenue,
    COUNT(*) FILTER (WHERE status_id = 143) AS lost_count
FROM kommo_deals
WHERE closed_at >= NOW() - INTERVAL '12 weeks'
GROUP BY 1, 2
ORDER BY 1 DESC, 3 DESC;

Win Rate по менеджеру:

SELECT
    responsible_name,
    COUNT(*) FILTER (WHERE status_id = 142) AS won,
    COUNT(*) FILTER (WHERE status_id = 143) AS lost,
    ROUND(100.0 *
        COUNT(*) FILTER (WHERE status_id = 142) /
        NULLIF(COUNT(*) FILTER (WHERE status_id IN (142, 143)), 0)
    , 1) AS win_rate_pct,
    SUM(price) FILTER (WHERE status_id = 142) AS total_revenue
FROM kommo_deals
WHERE closed_at >= NOW() - INTERVAL '90 days'
GROUP BY responsible_name
ORDER BY win_rate_pct DESC;

Redash REST API: получение результатов запроса

Redash предоставляет REST API для программного доступа к результатам. Используется для интеграций (например, отправить данные в Slack):

REDASH_URL = 'https://redash.yourcompany.com'
REDASH_API_KEY = 'your_user_api_key'  # из Settings -> API Key

def get_query_results(query_id: int) -> dict:
    # Сначала запустить (обновить) запрос
    requests.post(
        f'{REDASH_URL}/api/queries/{query_id}/refresh',
        headers={'Authorization': f'Key {REDASH_API_KEY}'}
    )
    # Получить результаты
    response = requests.get(
        f'{REDASH_URL}/api/queries/{query_id}/results.json',
        headers={'Authorization': f'Key {REDASH_API_KEY}'}
    )
    return response.json()['query_result']['data']['rows']

# Пример: получить топ-3 менеджера за неделю и отправить в Slack
rows = get_query_results(WEEKLY_MANAGERS_QUERY_ID)
for row in rows[:3]:
    print(f"{row['responsible_name']}: {row['won_count']} сделок")

Redash Embed в Slack/Notion

Redash поддерживает публикацию дашбордов по ссылке. Для внутреннего использования — без дополнительной аутентификации через ?api_key= в URL iframe.

Еженедельный автоматический отчёт в Slack:

import schedule

def send_weekly_report():
    rows = get_query_results(WEEKLY_SUMMARY_QUERY_ID)
    text_lines = [f'*Итоги недели:*']
    for row in rows:
        text_lines.append(
            f"{row['responsible_name']}: {row['won_count']} Won, "
            f"${row['won_revenue']:,.0f} выручка"
        )
    text_lines.append(f'\n<{REDASH_URL}/dashboard/sales|Открыть дашборд>')

    requests.post(SLACK_WEBHOOK_URL, json={'text': '\n'.join(text_lines)})

schedule.every().monday.at('09:00').do(send_weekly_report)

Реальный кейс

B2B SaaS-компания (30 сотрудников, EU-рынок, Kommo + self-hosted infrastructure):

  • До: head of sales каждый понедельник запрашивал отчёты у менеджеров вручную. Данные приходили в разных форматах, занимали 2–3 часа на сводку.
  • После: ETL-скрипт каждый час синхронизирует Kommo -> Postgres. Redash-дашборд с конверсией воронки, win rate по менеджерам и динамикой выручки обновляется в реальном времени. Еженедельный отчёт приходит в Slack каждый понедельник в 9:00 автоматически.
  • Выбор Redash: команда технически грамотная, аналитик пишет SQL — Redash идеально подходит. Metabase сочли избыточным по UI, Superset — сложным в настройке.

Схожий паттерн с Apache Superset — в статье Kommo + Superset: там мощнее визуализации, но выше порог настройки.

Для кого актуально

  • В команде есть аналитик или разработчик, который пишет SQL
  • Нужна self-hosted BI без Looker, Tableau или Metabase Cloud
  • Важен контроль над данными — никаких сторонних облаков с данными клиентов
  • Задача: дашборды для head of sales с конверсией, win rate, pipeline по менеджерам
  • Kommo не даёт достаточно гибкости в стандартных отчётах

Часто задаваемые вопросы

Redash self-hosted — насколько сложно развернуть?

Redash разворачивается через Docker Compose за 15–30 минут на любом VPS. Официальный docker-compose.yml включает Postgres (для метаданных Redash), Redis и сам сервер. Основная сложность — настройка подключения к вашему Postgres с данными Kommo и выпуск SSL-сертификата для домена.

Как часто нужно синхронизировать данные из Kommo?

Для оперативных дашбордов (менеджеры смотрят в течение дня) — каждые 15–30 минут. Для еженедельных отчётов руководителю — раз в час или по расписанию. Kommo API поддерживает фильтрацию по updated_at — incremental load не нагружает ни API, ни базу.

Можно ли подключить Redash напрямую к Kommo без базы данных?

Нет. Redash работает с SQL-совместимыми источниками: Postgres, MySQL, BigQuery, ClickHouse и др. Kommo API не является SQL-источником. Промежуточная БД обязательна — это часть архитектуры.

Redash vs Google Data Studio (Looker Studio) для Kommo-аналитики?

Looker Studio — облачный инструмент, не требует инфраструктуры, проще для нетехнических пользователей. Redash — self-hosted, полный контроль данных, SQL-ориентированный. Если данные клиентов не могут покидать EU-периметр — Redash. Если нужна быстрая визуализация без DevOps — Looker Studio.

Нужен ли платный Redash?

Redash полностью open-source (BSD лицензия). Коммерческая поддержка от airSlate доступна, но для большинства компаний self-hosted версия достаточна. Hosted-версия (redash.io) была закрыта — сейчас только self-hosting.

Итого

  • Паттерн: ETL Kommo API -> Postgres (incremental, каждые 15–30 мин) -> Redash SQL-запросы -> дашборды
  • Ключевые метрики: конверсия воронки, win rate по менеджерам, динамика выручки по неделям
  • Redash REST API: GET /api/queries/{id}/results.json — получение результатов для внешних интеграций (Slack-отчёты)
  • Self-hosted на Docker Compose: полный контроль данных, никакого вендор-локина
  • Типовой срок: ETL + схема — 1 неделя, дашборды — ещё 1 неделя

Если у вас Kommo и вы хотите self-hosted BI без Tableau и Looker — опишите какие метрики нужны head of sales. Exceltic.dev спроектирует схему БД и ключевые запросы для дашборда.

Ещё статьи

Все →