HubSpot + Hotjar: почему записи сессий не попадают в Deal Timeline

Нативная интеграция Hotjar с HubSpot отправляет данные о сессиях только в Contact Timeline - не в карточку сделки. Менеджер по продажам, открывающий Deal, не видит ни записей экрана, ни данных о поведении потенциального покупателя. Чтобы сессии появились именно в Deal Timeline, нужна кастомная интеграция через HubSpot Timeline Events API или Engagements API.

Эта статья объясняет, почему так устроена нативная интеграция, что конкретно теряет отдел продаж, и как построить правильный pipeline: от захвата recording URL на стороне Hotjar до создания события в карточке конкретной сделки.

В проектах по настройке HubSpot мы видим одну и ту же картину: команда маркетинга радуется, что Hotjar «подключён к CRM», а sales-менеджер при этом вручную ищет сессии в отдельном интерфейсе Hotjar по email-адресу лида. Данные есть, но они недоступны там, где принимается решение о закрытии сделки.

Что даёт нативная интеграция Hotjar с HubSpot - и чего она не даёт

Нативная интеграция Hotjar + HubSpot - это подключение через маркетплейс HubSpot, которое устанавливается в несколько кликов и не требует кода.

По состоянию на Q2 2026, нативная интеграция умеет:

  • Отправлять данные сессий (duration, rage-clicks, u-turns, referrer URL) в Contact Timeline в HubSpot
  • Передавать ответы на Hotjar-опросы в Contact Timeline
  • Создавать списки контактов на основе Hotjar-свойств (например, «провёл более 5 минут на странице pricing»)
  • Триггерить HubSpot-автоматизации на основе Hotjar-событий

Но нативная интеграция не умеет:

  • Отправлять данные в Deal Timeline - только в Contact Timeline
  • Передавать прямые ссылки на конкретные recording URL в HubSpot
  • Привязывать поведенческие данные к конкретной сделке, а не к контакту
  • Поддерживать User Attributes Hotjar - атрибуты пользователя не передаются в HubSpot

Это принципиальное ограничение архитектуры: Hotjar работает с понятием «посетитель» (visitor/contact), а менеджер по продажам работает с понятием «сделка» (deal). Нативная интеграция эту связь не устанавливает.

Почему данные сессий не попадают в Deal Timeline

Дело не в «недоработке» интеграции - это следствие разных моделей данных.

Hotjar идентифицирует пользователя по email или visitor ID. Когда посетитель оставляет форму или проходит опрос, Hotjar отправляет событие в HubSpot и связывает его с Contact-объектом по email.

HubSpot-сделка - это отдельный объект в CRM, связанный с Contact через ассоциацию. Нативная интеграция Hotjar не знает о существовании конкретной сделки и не умеет устанавливать ассоциацию «событие -> сделка».

Дополнительно: Hotjar передаёт данные через контактные свойства (contact properties) и Timeline Events для объекта Contact. HubSpot Timeline Events API позволяет создавать события на объектах Contact, Company, Deal или Ticket - но нативная интеграция Hotjar использует только Contact.

Поэтому даже если сессия успешно записана в Contact Timeline, менеджер в карточке Deal её не видит: он должен выйти из Deal, открыть связанный Contact, найти вкладку Activity, и уже там искать Hotjar-события. На практике этого никто не делает.

Что конкретно теряет команда продаж

Представьте типичный сценарий: лид посетил страницу ценообразования четыре раза за неделю, потратил 8 минут на enterprise-тариф, прошёл Hotjar-опрос «что вас останавливает от покупки» и написал «слишком дорого для старта». Менеджер звонит лиду, не видя этого контекста, и начинает разговор стандартным скриптом.

Потери конкретны:

  • Контекст перед звонком - менеджер не знает, какие страницы смотрел лид и сколько времени провёл
  • Сигналы готовности к покупке - посещение pricing page 4 раза за неделю - это сильный buying signal, который нигде не виден в Deal
  • Данные для квалификации - enterprise-поведение (изучение детальных условий, FAQ, security docs) отличается от SMB-поведения, и это видно в записях
  • Контекст для передачи сделки - когда SDR передаёт сделку AE, поведенческий контекст теряется полностью

В типовом B2B-пайплайне с циклом продаж 30-90 дней и несколькими стейкхолдерами этот контекст критичен. Похожая проблема возникает и с другими инструментами: например, нативная интеграция HubSpot + Zoom тоже не привязывает записи встреч к конкретной сделке.

Правильный подход - кастомная интеграция

Цель: каждый раз, когда Hotjar фиксирует значимое поведение идентифицированного пользователя, в Deal Timeline этого пользователя автоматически появляется запись со ссылкой на Hotjar-сессию.

Захват recording URL на стороне Hotjar

Hotjar не предоставляет recording URL в реальном времени через webhook. Обходной путь - использовать Hotjar Identify API для передачи пользовательских атрибутов, которые затем можно использовать для фильтрации записей.

Для захвата ссылки на сессию применяется другой подход: Hotjar формирует recording URL в формате https://insights.hotjar.com/sites/{site_id}/sessions/{session_id}. Session ID доступен через cookie _hjSessionUser_{site_id} или через Hotjar JS API.

При идентификации пользователя передайте его email и контекст в Hotjar:

// Идентификация пользователя в Hotjar
window.hj('identify', userId, {
  email: userEmail,
  plan: 'enterprise',
  deal_stage: 'demo_scheduled'
});

// Захват session ID из cookie для формирования recording URL
function getHotjarSessionId(siteId) {
  const cookieName = `_hjSessionUser_${siteId}`;
  const cookies = document.cookie.split(';');
  for (let c of cookies) {
    const [name, value] = c.trim().split('=');
    if (name === cookieName) {
      try {
        const parsed = JSON.parse(decodeURIComponent(value));
        return parsed.userId; // Это visitor ID, используется в URL записи
      } catch (e) { return null; }
    }
  }
  return null;
}

// Фиксация значимого события с передачей в бэкенд
function trackKeyBehavior(eventName, pageUrl, siteId) {
  const visitorId = getHotjarSessionId(siteId);
  const recordingUrl = visitorId
    ? `https://insights.hotjar.com/sites/${siteId}/sessions?filters=visitor_id:${visitorId}`
    : null;

  fetch('/api/crm/hotjar-event', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email: window.__userEmail, // email идентифицированного пользователя
      event: eventName,
      page: pageUrl,
      hotjar_url: recordingUrl,
      timestamp: new Date().toISOString()
    })
  });
}

// Пример: фиксация посещения страницы pricing
if (window.location.pathname.includes('/pricing')) {
  trackKeyBehavior('pricing_page_visited', window.location.href, YOUR_SITE_ID);
}

Для событий на основе опросов Hotjar поддерживает webhook: при сабмите опроса отправляется POST-запрос с email пользователя и ответами. Это более надёжный trigger для создания записи в CRM.

Timeline Event в HubSpot Deal через Timeline Events API

HubSpot Timeline Events API позволяет создавать кастомные события на объектах Contact, Company, Deal или Ticket. Событие отображается в Activity Timeline объекта.

Для создания события на Deal нужно:

  1. Создать Event Template через API или UI (Settings -> Integrations -> Private Apps)
  2. При создании шаблона указать objectType: DEAL
  3. Отправлять события через POST https://api.hubapi.com/crm/v3/timeline/events

Альтернативный подход, который не требует предварительного создания шаблона - создать Note через Engagements API и привязать её к Deal:

import requests
import json
from datetime import datetime

HUBSPOT_TOKEN = "your_private_app_token"
BASE_URL = "https://api.hubspot.com"

headers = {
    "Authorization": f"Bearer {HUBSPOT_TOKEN}",
    "Content-Type": "application/json"
}

def find_deal_by_contact_email(email: str) -> str | None:
    """Найти активную сделку по email контакта."""
    # Шаг 1: найти контакт
    search_payload = {
        "filterGroups": [{
            "filters": [{
                "propertyName": "email",
                "operator": "EQ",
                "value": email
            }]
        }],
        "properties": ["email", "hs_object_id"]
    }
    r = requests.post(
        f"{BASE_URL}/crm/v3/objects/contacts/search",
        headers=headers,
        json=search_payload
    )
    contacts = r.json().get("results", [])
    if not contacts:
        return None

    contact_id = contacts[0]["id"]

    # Шаг 2: получить ассоциированные сделки
    r = requests.get(
        f"{BASE_URL}/crm/v4/objects/contacts/{contact_id}/associations/deals",
        headers=headers
    )
    associations = r.json().get("results", [])
    if not associations:
        return None

    # Возвращаем первую активную сделку
    return associations[0]["toObjectId"]


def create_hotjar_note_on_deal(
    deal_id: str,
    contact_id: str,
    hotjar_url: str,
    event_name: str,
    page_url: str
) -> dict:
    """Создать заметку с ссылкой на Hotjar-сессию в Deal Timeline."""
    note_body = (
        f"Hotjar session: {event_name}\n"
        f"Page: {page_url}\n"
        f"Recording: {hotjar_url}"
    )

    payload = {
        "properties": {
            "hs_note_body": note_body,
            "hs_timestamp": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
        },
        "associations": [
            {
                "to": {"id": deal_id},
                "types": [{
                    "associationCategory": "HUBSPOT_DEFINED",
                    "associationTypeId": 214  # Note -> Deal
                }]
            },
            {
                "to": {"id": contact_id},
                "types": [{
                    "associationCategory": "HUBSPOT_DEFINED",
                    "associationTypeId": 202  # Note -> Contact
                }]
            }
        ]
    }

    r = requests.post(
        f"{BASE_URL}/crm/v3/objects/notes",
        headers=headers,
        json=payload
    )
    return r.json()


def handle_hotjar_event(event_data: dict):
    """Обработчик входящего события от Hotjar."""
    email = event_data.get("email")
    if not email:
        return {"error": "no email"}

    deal_id = find_deal_by_contact_email(email)
    if not deal_id:
        return {"error": "no deal found"}

    # Получить contact_id для ассоциации
    r = requests.post(
        f"{BASE_URL}/crm/v3/objects/contacts/search",
        headers=headers,
        json={
            "filterGroups": [{"filters": [{"propertyName": "email", "operator": "EQ", "value": email}]}]
        }
    )
    contact_id = r.json()["results"][0]["id"]

    result = create_hotjar_note_on_deal(
        deal_id=deal_id,
        contact_id=contact_id,
        hotjar_url=event_data.get("hotjar_url", ""),
        event_name=event_data.get("event", "session"),
        page_url=event_data.get("page", "")
    )
    return result

Аутентификация: Private App Token, создаётся в Settings -> Integrations -> Private Apps. Требуемые скоупы: crm.objects.notes.write, crm.objects.deals.read, crm.objects.contacts.read.

Привязка к конкретной сделке, а не контакту

Ключевой момент: один контакт может быть связан с несколькими сделками. Логика выбора сделки для привязки события:

  • По стадии: выбирать сделку в активной стадии (не closedwon, не closedlost)
  • По дате создания: брать самую последнюю открытую сделку
  • По кастомному полю: передавать deal_id явно из фронтенда, если он известен

Для B2B-сценариев с длинным циклом продаж рекомендуется третий вариант: при идентификации пользователя на сайте передавать deal_id через Hotjar Identify API, если пользователь авторизован в продукте или перешёл по персонализированной ссылке.

Аналогичная проблема с привязкой данных к сделке (а не к контакту) существует и в нативной интеграции HubSpot + Intercom, и в HubSpot + Slack - нативные коннекторы работают на уровне контакта, а не сделки.

Реальный кейс: что изменилось после интеграции

В одном из проектов для B2B SaaS-компании (команда продаж 8 человек, средний цикл сделки 45 дней, чек $12,000-40,000) мы построили этот pipeline за три недели.

До интеграции: менеджеры иногда открывали Hotjar вручную, но делали это в лучшем случае перед 20-30% демо-звонков. Для поиска нужной сессии по email уходило 5-10 минут.

После интеграции в каждой карточке Deal автоматически появляются:

  • Заметки при каждом посещении страниц pricing, features, security
  • Ссылки на Hotjar-сессии с указанием длительности и триггерных событий (rage-click, u-turn)
  • Ответы на exit-опросы с привязкой к дате посещения

Результат за первые два месяца:

  • Средняя подготовка к демо сократилась с 25 до 8 минут
  • Менеджеры стали упоминать конкретные страницы и возражения из Hotjar-сессий в 60% звонков
  • Конверсия демо -> коммерческое предложение выросла на 18% - команда связывает это в том числе с лучшим пониманием контекста лида

Если вы строите аналитику продаж, которая замыкает поведение на сайте с CRM-данными, посмотрите на Prooflytics - платформу, которая собирает multi-touch атрибуцию из рекламных кабинетов, CRM и поведения на сайте в единый дашборд.

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

Эта интеграция нужна командам, у которых одновременно выполняются несколько условий:

  • B2B-продукт с циклом продаж от 2 недель и чеком от $3,000-5,000
  • На сайте есть значимые страницы (pricing, enterprise features, case studies), которые лиды изучают до покупки
  • Hotjar уже установлен и дает реальные сессии идентифицированных пользователей
  • Sales-команда работает в HubSpot Deal - именно там принимаются решения о следующем шаге
  • SDR/AE-модель: данные о поведении лида нужно передавать вместе со сделкой

Для e-commerce и PLG-продуктов (где нет активной роли продавца) нативной интеграции Hotjar с HubSpot обычно достаточно - там важнее Contact Timeline для маркетинговых автоматизаций.

Аналогичный кастомный подход применяется и для Kommo CRM, когда нужно привязать поведенческие данные именно к воронке продаж, а не к контакту.

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

Hotjar говорит, что интеграция с HubSpot включает «session recordings в Contact Timeline» - это значит, что они попадают в Deal?

Нет. Contact Timeline и Deal Timeline - это разные объекты в HubSpot. Данные, которые Hotjar отправляет в Contact Timeline, видны в карточке контакта на вкладке Activity. Чтобы их увидеть из карточки Deal, нужно перейти в связанный Contact - это неудобно и на практике не делается. Нативная интеграция не создаёт события в Deal Timeline.

Можно ли использовать HubSpot Workflow для перемещения Hotjar-событий из Contact в Deal?

Частично. HubSpot Workflow позволяет копировать значения контактных свойств в свойства сделки. Но Hotjar-события - это Timeline Events, а не свойства контакта. Timeline Events нельзя «скопировать» в сделку через Workflow. Можно создать кастомное свойство контакта «Last Hotjar Session URL» и через Workflow копировать его значение в свойство сделки - это более простое решение, хотя и не даёт полной истории событий в Deal Timeline.

Нужен ли для кастомной интеграции отдельный сервер?

Да, нужен backend-сервис, который принимает события с фронтенда (или Hotjar webhook) и делает вызовы к HubSpot API. Это может быть небольшой FastAPI или Express сервис на любом хостинге. Альтернатива - AWS Lambda или Cloudflare Workers для serverless-архитектуры. Бессерверный вариант проще в поддержке для команд без DevOps-ресурса.

Hotjar Events API vs webhook - что выбрать для триггера?

Hotjar webhook (доступен при survey submission) - более надёжный триггер, потому что работает на стороне сервера и не зависит от браузера пользователя. JS Events API на фронтенде может теряться при закрытии вкладки или сетевых ошибках. Для production-интеграции рекомендуется комбинация: JS-события для поведенческих триггеров (посещение pricing, время на странице) + Hotjar webhook для опросов.

Как обрабатывать случай, когда у контакта несколько открытых сделок?

Лучший подход - передавать deal_id явно из фронтенда, если он известен (например, пользователь авторизован в продукте и его сделка известна). Если deal_id неизвестен, выбирать сделку по дате последнего изменения среди активных стадий. При множестве сделок создавать события во всех активных - это безопаснее, чем потенциально потерять событие.

Что делать дальше

  • Нативная интеграция Hotjar + HubSpot работает только на уровне Contact Timeline
  • Deal Timeline требует отдельного pipeline: захват события на фронтенде -> backend -> HubSpot Notes API с ассоциацией к сделке
  • Hotjar Identify API и JS-события дают нужные данные, включая ссылки на сессии
  • HubSpot Notes API с associationTypeId: 214 создаёт заметку, видимую в Deal Timeline

Если вы используете HubSpot с Hotjar и хотите, чтобы менеджеры по продажам видели поведение лидов прямо в карточке сделки - опишите вашу ситуацию команде Exceltic.dev. Разберём стек, определим правильную архитектуру привязки событий к сделкам и оценим объём работ.

Ещё статьи

Все →