Customer.io - платформа email-автоматизации, ориентированная на data-driven сценарии: ветвление кампаний по атрибутам профиля, поведенческие триггеры, A/B тесты на уровне отправки. В B2B sales это означает возможность отправить разные последовательности писем исходя из индустрии лида, размера сделки или этапа воронки в Kommo. Без интеграции данные из CRM и данные в Customer.io существуют изолированно.
Типичная проблема: лид перешёл в этап «Коммерческое предложение» в Kommo - и должна автоматически запуститься nurture-последовательность в Customer.io. Или: клиент открыл три письма подряд - это сигнал интереса, и в Kommo должна появиться задача позвонить. Без двусторонней интеграции оба сценария требуют ручного вмешательства.
В этой статье разберём bidirectional-связку Kommo - Customer.io: события из воронки запускают email-кампании, а engagement-данные Customer.io возвращаются в карточку сделки.
Почему нативной интеграции нет
Customer.io не имеет готового виджета для Kommo. В Customer.io доступны прямые интеграции с Segment, Twilio, Salesforce и несколькими другими - Kommo в этот список не входит. Zapier поддерживает Customer.io, но только в одну сторону (Zapier -> Customer.io), и не передаёт полный набор атрибутов сделки, необходимый для data-driven ветвления.
Customer.io - платформа для отправки transactional и marketing email/push/SMS сообщений на основе событий и атрибутов пользователей. Отличается от Mailchimp/SendGrid акцентом на сегментацию по поведению и разветвлённые workflow.
Архитектура двусторонней интеграции
Направление 1 - Kommo -> Customer.io:
- Kommo webhook (смена этапа / новый лид) -> обновление Customer.io профиля
- Атрибуты сделки (размер, индустрия, этап) -> Customer.io person attributes
- Смена этапа -> Customer.io custom event -> триггер Campaign
Направление 2 - Customer.io -> Kommo:
- Customer.io webhook (email opened, clicked, unsubscribed) -> заметка в Kommo
- Несколько opens подряд -> задача менеджеру позвонить
Реализация: Kommo -> Customer.io
Шаг 1 - подписка на Kommo webhook:
В Kommo настраиваем webhook на события: смена статуса сделки, добавление нового лида. В Kommo Admin -> Настройки -> Webhooks.
from flask import Flask, request
import requests, base64
app = Flask(__name__)
CIO_SITE_ID = "your_site_id" # из Customer.io Account -> API Credentials
CIO_API_KEY = "your_api_key"
CIO_TRACK_BASE = "https://track.customer.io/api/v1"
KOMMO_DOMAIN = "yourdomain.kommo.com"
KOMMO_TOKEN = "your_kommo_token"
KOMMO_BASE = f"https://{KOMMO_DOMAIN}/api/v4"
def cio_headers():
creds = base64.b64encode(f"{CIO_SITE_ID}:{CIO_API_KEY}".encode()).decode()
return {
"Authorization": f"Basic {creds}",
"Content-Type": "application/json"
}
@app.route("/kommo/webhook", methods=["POST"])
def kommo_webhook():
data = request.json
# Kommo отправляет данные в формате {leads: {status_changed: [...]}}
for event_type, leads in data.items():
for entity_type, items in leads.items():
for item in items:
if entity_type == "status_changed":
on_lead_status_changed(item)
elif entity_type == "add":
on_lead_added(item)
return "ok", 200
Шаг 2 - передать данные Kommo в Customer.io:
def get_kommo_lead_full(lead_id: int) -> dict:
hs = requests.Session()
hs.headers.update({
"Authorization": f"Bearer {KOMMO_TOKEN}",
"Content-Type": "application/json"
})
r = hs.get(f"{KOMMO_BASE}/leads/{lead_id}",
params={"with": "contacts,custom_fields"})
lead = r.json()
# Находим email контакта
contacts = lead.get("_embedded", {}).get("contacts", [])
email = ""
for c in contacts:
for field in c.get("custom_fields_values") or []:
if field.get("field_type") == "EMAIL":
vals = field.get("values", [])
if vals:
email = vals[0].get("value", "")
break
return {"id": lead_id, "email": email, "lead": lead}
def on_lead_status_changed(item: dict):
lead_id = item.get("id")
status_id = item.get("status_id")
pipeline = item.get("pipeline_id")
ctx = get_kommo_lead_full(lead_id)
if not ctx["email"]:
return
lead = ctx["lead"]
email = ctx["email"]
# Карта этапов -> понятные названия
stage_map = {
1: "new", 2: "in_contact", 3: "proposal_sent",
4: "negotiation", 142: "won", 143: "lost"
}
stage_name = stage_map.get(status_id, f"stage_{status_id}")
# Обновить атрибуты в Customer.io
cio = requests.Session()
cio.headers.update(cio_headers())
cio.put(f"{CIO_TRACK_BASE}/customers/{email}", json={
"kommo_lead_id": str(lead_id),
"kommo_stage": stage_name,
"kommo_stage_id": status_id,
"kommo_pipeline": pipeline,
"deal_value": lead.get("price", 0),
"responsible_name": lead.get("responsible_user_id"),
})
# Отправить событие для триггера Campaign
cio.post(f"{CIO_TRACK_BASE}/customers/{email}/events", json={
"name": "kommo_stage_changed",
"data": {
"stage": stage_name,
"stage_id": status_id,
"lead_id": lead_id,
"deal_value": lead.get("price", 0),
}
})
def on_lead_added(item: dict):
ctx = get_kommo_lead_full(item.get("id"))
if not ctx["email"]:
return
lead = ctx["lead"]
email = ctx["email"]
cio = requests.Session()
cio.headers.update(cio_headers())
# Идентифицировать нового пользователя в Customer.io
cio.put(f"{CIO_TRACK_BASE}/customers/{email}", json={
"kommo_lead_id": str(lead.get("id")),
"kommo_stage": "new",
"deal_value": lead.get("price", 0),
"created_at": lead.get("created_at"),
})
# Событие для welcome-sequence
cio.post(f"{CIO_TRACK_BASE}/customers/{email}/events", json={
"name": "kommo_lead_created",
"data": {"lead_id": lead.get("id")}
})
Реализация: Customer.io -> Kommo
Шаг 3 - обработка email-событий из Customer.io:
В Customer.io настраиваем Reporting Webhook: Workspace -> Settings -> Reporting Webhooks. Подписываемся на email_opened, email_clicked, email_unsubscribed.
@app.route("/customerio/webhook", methods=["POST"])
def cio_webhook():
# Customer.io подписывает webhook через X-CIO-Signature (HMAC-SHA256)
event_type = request.json.get("metric", "")
customer_id = request.json.get("customer_id", "") # это email
data = request.json.get("data", {})
if event_type in ("email_opened", "email_clicked"):
on_email_engagement(customer_id, event_type, data)
elif event_type == "email_unsubscribed":
on_email_unsubscribed(customer_id, data)
return "ok", 200
def find_kommo_lead_by_email(email: str) -> int | None:
hs = requests.Session()
hs.headers.update({
"Authorization": f"Bearer {KOMMO_TOKEN}",
"Content-Type": "application/json"
})
r = hs.get(f"{KOMMO_BASE}/contacts", params={"query": email, "limit": 1})
contacts = r.json().get("_embedded", {}).get("contacts", [])
if not contacts:
return None
contact_id = contacts[0]["id"]
r2 = hs.get(f"{KOMMO_BASE}/contacts/{contact_id}/links")
links = r2.json().get("_embedded", {}).get("links", [])
for l in links:
if l.get("to_entity_type") == "leads":
return l["to_entity_id"]
return None
# Счётчик открытий для hot-lead триггера
_open_counts: dict = {}
def on_email_engagement(email: str, event_type: str, data: dict):
lead_id = find_kommo_lead_by_email(email)
if not lead_id:
return
event_label = {"email_opened": "открыл письмо", "email_clicked": "кликнул по ссылке"}
subject = data.get("subject", "")
hs = requests.Session()
hs.headers.update({
"Authorization": f"Bearer {KOMMO_TOKEN}",
"Content-Type": "application/json"
})
hs.post(f"{KOMMO_BASE}/leads/notes", json=[{
"entity_id": lead_id,
"note_type": "common",
"params": {"text": f"Customer.io: {email} {event_label[event_type]}. Тема: {subject}"}
}])
# Hot-lead логика: 3+ открытия = звонить
key = f"{email}:opens"
_open_counts[key] = _open_counts.get(key, 0) + 1
if _open_counts[key] >= 3:
import time
hs.post(f"{KOMMO_BASE}/tasks", json=[{
"task_type_id": 1,
"entity_type": "leads",
"entity_id": lead_id,
"text": f"{email} открыл письма 3 раза - высокий интерес. Позвоните сегодня.",
"complete_till": int(time.time()) + 28800, # 8 часов
}])
_open_counts[key] = 0 # сброс
В продакшене _open_counts замените на Redis-счётчик с TTL 48 часов - это предотвратит накопление устаревших данных.
Реальный кейс
B2B SaaS: 200 лидов в месяц через inbound, 4-недельный цикл продажи. До интеграции: Customer.io campains запускались вручную через ручной CSV-экспорт из Kommo раз в неделю. 20-30% лидов выпадали из nurture-последовательности из-за задержки синхронизации.
После двусторонней интеграции:
- Каждый новый лид в Kommo автоматически идентифицируется в Customer.io
- Смена этапа запускает нужную Campaign в течение секунды
- «Горячие» лиды (3+ открытия) получают задачу менеджеру автоматически
- 0 ручных экспортов CSV
Для кого актуально
B2B-команды, которые сочетают sales-воронку в Kommo с маркетинговой автоматизацией через Customer.io. Особенно эффективно для inbound-моделей, где лид проходит через email nurturing параллельно с работой менеджера.
Аналогичная интеграция для другой email-платформы описана в Kommo + Encharge. Если вы используете SendGrid для transactional email - там другая архитектура: смотрите Kommo + SendGrid.
Часто задаваемые вопросы
Как ветвить Customer.io Campaign по размеру сделки из Kommo?
В Customer.io Campaign добавьте Segment Filter по атрибуту deal_value - он обновляется при каждой смене этапа. Campaign выходит только на персон, у которых deal_value >= 5000. Атрибуты передаются через Track API через PUT /customers/{email} - именно это мы делаем в on_lead_status_changed.
Нужен ли отдельный Customer.io тариф для webhook reporting?
Reporting Webhooks доступны на всех платных тарифах Customer.io: Essentials и выше. На Free тарифе webhooks не поддерживаются. Verify в Customer.io -> Settings -> Billing.
Как отписка в Customer.io отражается в Kommo?
В нашем примере email_unsubscribed создаёт заметку в Kommo и может изменить кастомное поле статуса подписки. Логику можно расширить: если лид отписался - автоматически ставить задачу менеджеру выяснить причину или переводить сделку на этап «Отказ».
Можно ли синхронизировать custom fields Kommo с Customer.io атрибутами?
Да. В get_kommo_lead_full разбираем custom_fields_values из Kommo и маппируем нужные поля в Customer.io атрибуты. Например, поле «Индустрия» из Kommo становится атрибутом industry в Customer.io для сегментации campains по вертикалям.
Итог
Kommo + Customer.io bidirectional-интеграция даёт полную картину: воронка в CRM управляет email-автоматизацией, а engagement-данные возвращаются в CRM. Схема:
- Kommo webhook (статус, новый лид) -> Customer.io Track API: обновление атрибутов и событие-триггер
- Customer.io Reporting Webhook -> Kommo: заметка об открытии, задача на горячего лида
- Customer.io Campaign сегментируется по атрибутам сделки (
deal_value,kommo_stage,industry)
Если ваша команда работает с Kommo и Customer.io - опишите задачу команде Exceltic.dev. Настроим двустороннюю синхронизацию под вашу структуру воронки и кампаний.