Sigma Computing is a cloud BI platform with a spreadsheet-style interface built on top of a data warehouse. For B2B teams that manage sales in Kommo and need full-featured analytics - conversion rates by stage, pipeline velocity, cohort analysis - Sigma offers capabilities that standard CRM analytics simply cannot provide.
The integration is built through an ETL pipeline: Kommo API -> Python script -> PostgreSQL -> Sigma connects to PostgreSQL as a data source. The Sigma API (OAuth2 client_credentials) is used for programmatically managing embed links and Input Tables. For most use cases, you only need to configure the ETL once and then work entirely within the Sigma interface.
Sigma Computing is a BI tool that operates on top of a cloud data warehouse (Snowflake, BigQuery, Redshift, PostgreSQL). It differs from Metabase and Superset in that it allows analysts to work in a spreadsheet interface without writing SQL, while still maintaining full data model flexibility.
Why Native CRM Analytics Falls Short
Kommo Analytics shows standard metrics: deal counts by stage, funnel, manager activity. But for board reports and strategic decisions, you need more: cohort analysis (which clients from Q3 2025 converted in Q1 2026), multi-touch attribution, cross-pipeline correlations, period-over-period comparisons with trend data.
The standard workaround is exporting a CSV from Kommo and loading it into Google Sheets. This works for one-off reports, but not for a live dashboard. Every update means a new export, a new import.
Architecture
Kommo API (deals, contacts, pipelines, events)
-> Python ETL script (daily cron / per webhook)
-> PostgreSQL (kommo_leads, kommo_contacts, kommo_events)
Sigma Computing
-> Connected Dataset: connected to PostgreSQL
-> Workbook with sales dashboard
-> (optional) Embed API -> iframe in internal portal
ETL: Kommo -> PostgreSQL
import requests, os, psycopg2
from datetime import datetime
KOMMO_SUBDOMAIN = os.environ["KOMMO_SUBDOMAIN"]
KOMMO_TOKEN = os.environ["KOMMO_ACCESS_TOKEN"]
DB_URL = os.environ["DATABASE_URL"] # postgres://user:pass@host/db
KOMMO_BASE = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4"
KOMMO_HDR = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
def fetch_leads(page: int = 1, limit: int = 250) -> list:
r = requests.get(
f"{KOMMO_BASE}/leads",
headers=KOMMO_HDR,
params={
"page": page,
"limit": limit,
"with": "contacts,pipeline,custom_fields_values",
},
)
if r.status_code == 204:
return []
r.raise_for_status()
return r.json().get("_embedded", {}).get("leads", [])
def fetch_all_leads() -> list:
all_leads = []
page = 1
while True:
batch = fetch_leads(page)
if not batch:
break
all_leads.extend(batch)
page += 1
return all_leads
def upsert_leads(conn, leads: list):
with conn.cursor() as cur:
cur.execute(
"CREATE TABLE IF NOT EXISTS kommo_leads ("
" id BIGINT PRIMARY KEY,"
" name TEXT,"
" status_id INT,"
" pipeline_id INT,"
" price BIGINT,"
" created_at TIMESTAMPTZ,"
" closed_at TIMESTAMPTZ,"
" updated_at TIMESTAMPTZ,"
" responsible INT,"
" loss_reason TEXT"
")"
)
for lead in leads:
cur.execute(
"INSERT INTO kommo_leads"
" (id, name, status_id, pipeline_id, price,"
" created_at, closed_at, updated_at, responsible)"
" VALUES (%s,%s,%s,%s,%s,"
" to_timestamp(%s), to_timestamp(%s), to_timestamp(%s), %s)"
" ON CONFLICT (id) DO UPDATE SET"
" name = EXCLUDED.name,"
" status_id = EXCLUDED.status_id,"
" price = EXCLUDED.price,"
" closed_at = EXCLUDED.closed_at,"
" updated_at = EXCLUDED.updated_at",
(
lead["id"],
lead.get("name"),
lead.get("status_id"),
lead.get("pipeline_id"),
lead.get("price", 0),
lead.get("created_at"),
lead.get("closed_at"),
lead.get("updated_at"),
lead.get("responsible_user_id"),
),
)
conn.commit()
def run_etl():
leads = fetch_all_leads()
print(f"Fetched {len(leads)} leads")
conn = psycopg2.connect(DB_URL)
upsert_leads(conn, leads)
conn.close()
print(f"ETL done: {datetime.now()}")
if __name__ == "__main__":
run_etl()
Connecting Sigma to PostgreSQL
In Sigma Admin Portal -> Connections -> New Connection:
- Type: PostgreSQL
- Host, Port, Database, User, Password - from your PostgreSQL instance
- After connecting: Sigma automatically discovers tables
From the kommo_leads table, create a Dataset in Sigma and add computed columns:
win_rate:CASE WHEN status_id = {won_id} THEN 1 ELSE 0 ENDdeal_duration_days:DATEDIFF('day', created_at, COALESCE(closed_at, NOW()))pipeline_stage: JOIN with thekommo_statusestable (if you export it)
Sigma API: Embed for Internal Portal
import time, hmac, hashlib, urllib.parse, os
SIGMA_CLIENT_ID = os.environ["SIGMA_CLIENT_ID"]
SIGMA_CLIENT_SECRET = os.environ["SIGMA_CLIENT_SECRET"]
SIGMA_EMBED_SECRET = os.environ["SIGMA_EMBED_SECRET"]
def get_sigma_token() -> str:
r = requests.post(
"https://aws-api.sigmacomputing.com/v2/auth/token",
data={
"grant_type": "client_credentials",
"client_id": SIGMA_CLIENT_ID,
"client_secret": SIGMA_CLIENT_SECRET,
},
)
r.raise_for_status()
return r.json()["access_token"]
def generate_embed_url(workbook_id: str,
user_email: str, user_team: str) -> str:
nonce = os.urandom(16).hex()
ts = str(int(time.time()))
params = {
"workbookId": workbook_id,
"email": user_email,
"team": user_team,
"nonce": nonce,
"time": ts,
}
query = urllib.parse.urlencode(params)
sig_input = f"/embed/explore?{query}"
signature = hmac.new(
SIGMA_EMBED_SECRET.encode(), sig_input.encode(), hashlib.sha256
).hexdigest()
return f"https://app.sigmacomputing.com/embed/explore?{query}&signature={signature}"
The embed URL can be passed into an iframe on an internal portal or dashboard page.
Real-World Case
A company with 4 pipelines in Kommo (different products) and a team of 25 people. Before the integration: an analyst prepared the board report manually every two weeks - 4-5 hours of exporting, cleaning, and building charts in Google Sheets. After: the ETL runs on a daily cron, and the Sigma dashboard updates in real time. The board gets a live report with no analyst involvement.
Who This Is For
B2B companies with 3+ pipelines in Kommo that need cross-pipeline analytics. Sigma is especially valued in companies where analysts are comfortable with a spreadsheet interface but need BI capabilities: custom metrics, drill-down, cohort analysis. If you already have PostgreSQL or a data warehouse, adding Sigma as a BI layer is minimally invasive.
Other analytics integrations: Kommo + Hex (Python notebooks), Kommo + Lightdash (dbt + BI).
Frequently Asked Questions
Does Sigma work with Snowflake instead of PostgreSQL?
Yes - Sigma was originally built for Snowflake. PostgreSQL is one of many supported connectors. For enterprise-scale volumes (10M+ records), we recommend Snowflake or BigQuery - PostgreSQL starts to slow down on large analytical queries.
How often should the ETL run?
It depends on your needs. For a daily board report - a nightly cron job. For a live sales dashboard - a webhook trigger on every deal change in Kommo (leads.update webhook) plus an incremental upsert by updated_at.
Does Sigma support Row Level Security for different managers?
Yes. Sigma supports User Attributes: when generating an embed URL, you pass userAttributes: {"region": "EU"}, and the Dataset filter automatically restricts data by that attribute. Each manager sees only their own deals.
How does Sigma differ from Metabase for this use case?
Metabase is easier to set up and cheaper. Sigma is stronger for custom calculations, the spreadsheet interface, and working with large data volumes. For teams with SQL analysts - Sigma provides more flexibility. For teams without technical analysts - Metabase with its Question builder is easier to use.
Summary
Kommo + Sigma Computing - a BI dashboard from CRM data:
- ETL: Kommo API -> Python -> PostgreSQL (upsert by id)
- Sigma: Connected Dataset on top of PostgreSQL -> workbook with metrics
- Sigma API: OAuth2 client_credentials, embed URL via HMAC signature
- Daily cron or webhook-triggered incremental sync
- Row Level Security via User Attributes for different roles
If your team wants to build sales analytics on top of Kommo and Sigma Computing - describe your needs to the Exceltic.dev team.