HubSpot + Facebook Lead Ads: что теряет нативная интеграция

HubSpot + Facebook Lead Ads: что теряет нативная интеграция

Facebook Lead Ads позволяет собирать контакты прямо в Meta — без перехода на сайт. Пользователь видит объявление, кликает, форма заполнена его данными из профиля, лид отправлен. HubSpot нативно интегрируется с Facebook Lead Ads через раздел Marketing -> Lead Capture -> Facebook Lead Ads. Выглядит как готовое решение. На практике — нативная интеграция работает, но теряет достаточно данных чтобы атрибуция была неточной, а CRM засорялась дублями.

Как работает нативная интеграция

Нативная интеграция HubSpot ↔ Facebook Lead Ads использует Meta Leads API: после заполнения формы Meta отправляет webhook -> HubSpot создаёт Contact. Настройка занимает 5 минут в интерфейсе. Проблемы начинаются после.

Что нативная интеграция умеет:
— Создать Contact из стандартных полей Lead Ad формы (имя, email, телефон)
— Добавить лиды в HubSpot List
— Запустить Workflow при создании контакта
— Маппить поля формы в стандартные HubSpot Contact properties

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

1. Маппинг кастомных полей — только частично

Lead Ad форма может содержать custom questions: «Ваша должность», «Размер команды», «Какой продукт интересует». Нативная интеграция не поддерживает прямой маппинг этих ответов в HubSpot Custom Properties. Данные либо теряются, либо складываются в notes — без возможности сегментировать по ним в CRM.

2. UTM-атрибуция не передаётся

Это главная боль. Пользователь кликает объявление с utm_campaign=summer_sale&utm_source=facebook. Нативная интеграция создаёт Contact, но UTM-параметры из URL объявления не попадают в Contact properties. HubSpot видит источник как «Facebook Lead Ads» — без разбивки по кампании, группе объявлений, креативу.

Результат: в Deals нет данных о том, из какой конкретно кампании пришёл лид. Маркетолог не может сравнить cost per deal по кампаниям.

3. Дубли существующих контактов

Если Contact с таким email уже есть в HubSpot — нативная интеграция создаёт второй Contact, а не обновляет существующий. Логика: нативная интеграция использует create endpoint, а не upsert. Итог: дубли, разрозненная история взаимодействий, ломаный Lifecycle Stage.

4. Conditional logic форм

Facebook Lead Ad форма поддерживает conditional questions: если ответил «Да» на вопрос 1 -> показать вопрос 2. Нативная интеграция не понимает условную логику — получает плоский массив ответов без учёта ветки. Сложные формы для квалификации лидов работают непредсказуемо.

5. Нет поддержки Instant Form версий

Meta постоянно обновляет формат Instant Forms. Нативная интеграция может не поддерживать новые типы полей сразу — задержка до официального обновления коннектора HubSpot.

Как это влияет на бизнес

Типичный сценарий: маркетолог запускает 4 кампании Facebook Lead Ads с разными креативами. Все лиды попадают в HubSpot с источником «Facebook Lead Ads». Через месяц нужно понять какая кампания даёт лучший cost per closed deal — данных нет. Оптимизация по CPL вместо CAC: дорогой канал финансируется, дешёвый режется.

Аналогичная проблема описана для HubSpot + Slack: нативная интеграция создаёт видимость работы, но теряет критичные данные.

Правильный подход: прямая интеграция через Lead Gen API

Шаг 1. Получить Lead в реальном времени через webhook:

from flask import Flask, request
import hmac, hashlib

app = Flask(__name__)

FACEBOOK_APP_SECRET = "your_app_secret"

@app.route("/webhooks/fb-leads", methods=["GET", "POST"])
def facebook_lead_webhook():
    if request.method == "GET":
        # Верификация endpoint
        challenge = request.args.get("hub.challenge")
        return challenge, 200

    payload = request.json
    for entry in payload.get("entry", []):
        for change in entry.get("changes", []):
            if change.get("field") == "leadgen":
                lead_id = change["value"]["leadgen_id"]
                form_id = change["value"]["form_id"]
                ad_id = change["value"].get("ad_id")
                campaign_id = change["value"].get("campaign_id")
                adset_id = change["value"].get("adset_id")

                lead_data = fetch_lead_data(lead_id)
                process_lead(lead_data, ad_id, campaign_id, adset_id)

    return "", 200

Шаг 2. Получить данные лида из Graph API:

import requests

FACEBOOK_ACCESS_TOKEN = "your_page_access_token"

def fetch_lead_data(lead_id: str) -> dict:
    resp = requests.get(
        f"https://graph.facebook.com/v19.0/{lead_id}",
        params={
            "access_token": FACEBOOK_ACCESS_TOKEN,
            "fields": "field_data,ad_id,campaign_id,adset_id,created_time,form_id"
        }
    )
    resp.raise_for_status()
    return resp.json()

def extract_fields(lead_data: dict) -> dict:
    # Конвертировать field_data в dict
    result = {}
    for item in lead_data.get("field_data", []):
        key = item.get("name", "")
        values = item.get("values", [])
        result[key] = values[0] if values else ""
    return result

Шаг 3. Upsert в HubSpot с UTM-атрибуцией:

import hubspot
from hubspot.crm.contacts import SimplePublicObjectInputForCreate
from hubspot.crm.contacts.exceptions import ApiException

hs_client = hubspot.Client.create(access_token="your_hubspot_private_app_token")

AD_NAME_CACHE = {}

def get_ad_name(ad_id: str) -> str:
    if ad_id in AD_NAME_CACHE:
        return AD_NAME_CACHE[ad_id]
    try:
        resp = requests.get(
            f"https://graph.facebook.com/v19.0/{ad_id}",
            params={"access_token": FACEBOOK_ACCESS_TOKEN, "fields": "name,effective_status"}
        )
        name = resp.json().get("name", ad_id)
        AD_NAME_CACHE[ad_id] = name
        return name
    except Exception:
        return ad_id

def process_lead(lead_data: dict, ad_id: str, campaign_id: str, adset_id: str):
    fields = extract_fields(lead_data)
    email = fields.get("email", "")
    if not email:
        return

    ad_name = get_ad_name(ad_id) if ad_id else ""

    contact_props = {
        "email": email,
        "firstname": fields.get("first_name", ""),
        "lastname": fields.get("last_name", ""),
        "phone": fields.get("phone_number", ""),
        # UTM-атрибуция через ad API данные
        "hs_analytics_source": "PAID_SOCIAL",
        "hs_analytics_source_data_1": "Facebook",
        "hs_analytics_source_data_2": campaign_id or "",
        # Кастомные properties (создать в HubSpot заранее)
        "fb_campaign_id": campaign_id or "",
        "fb_adset_id": adset_id or "",
        "fb_ad_id": ad_id or "",
        "fb_ad_name": ad_name,
        "fb_form_id": lead_data.get("form_id", ""),
        # Кастомные поля из формы (маппинг явный)
        "job_title": fields.get("job_title", ""),
        "company_size": fields.get("company_size", ""),
        "interested_product": fields.get("interested_in", ""),
        "lead_source": "Facebook Lead Ads",
    }

    # Upsert - обновить существующий контакт, не создавать дубль
    try:
        hs_client.crm.contacts.basic_api.create(
            simple_public_object_input_for_create=SimplePublicObjectInputForCreate(
                properties=contact_props
            )
        )
    except ApiException as e:
        if e.status == 409:  # Contact already exists
            # Получить существующий контакт и обновить
            existing = hs_client.crm.contacts.search_api.do_search(
                public_object_search_request={
                    "filterGroups": [{"filters": [
                        {"propertyName": "email", "operator": "EQ", "value": email}
                    ]}]
                }
            )
            if existing.results:
                contact_id = existing.results[0].id
                hs_client.crm.contacts.basic_api.update(
                    contact_id=contact_id,
                    simple_public_object_input={"properties": contact_props}
                )
        else:
            raise

Атрибуция: связать лид с закрытой сделкой

Передача campaign_id, adset_id, ad_id в Contact properties позволяет в HubSpot Reports сделать breakdown сделок по Facebook-кампании. Но это даёт атрибуцию только «последнего клика» — и только для лидов из Facebook Lead Ads.

Для полноценной атрибуции от рекламного клика до закрытой сделки через все каналы — Meta, Google, LinkedIn — нужна система, которая объединяет ad data с CRM-lifecycle. Prooflytics + Meta Ads решает именно это: первый клик -> атрибуция через fbclid -> сделка в HubSpot -> реальный CAC по кампании.

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

B2B SaaS (EU, 30–50 лидов из Facebook Lead Ads в месяц, HubSpot):

  • До: нативная интеграция. 100% лидов с источником «Facebook Lead Ads» без разбивки. В CRM — 18% дублей. Кастомные поля из форм (должность, размер компании) теряются.
  • После: прямая интеграция через Graph API webhook. UTM-атрибуция на уровне объявления. Upsert вместо create — дубли исчезли. Кастомные поля форм -> HubSpot Custom Properties -> сегментация в Deals.
  • Дополнительно: breakdown сделок по Facebook-кампаниям показал: кампания с CPL $45 давала cost per deal $890, кампания с CPL $110 — $420. Перераспределение бюджета -> -23% стоимости привлечения клиента.

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

  • Команды с 30+ лидами в месяц из Facebook Lead Ads — при меньшем объёме нативная интеграция терпима
  • Маркетинг с несколькими активными кампаниями — нужна разбивка по campaign_id
  • Компании с кастомными формами квалификации — conditional questions, custom fields
  • HubSpot + CRM-driven attribution: нативная интеграция ломает воронку отчётности

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

HubSpot Facebook Lead Ads интеграция платная?

Нативная интеграция доступна в бесплатном и платных планах HubSpot — отдельной платы нет. Facebook Graph API для получения лидов бесплатен при наличии одобренного бизнес-аккаунта Meta.

Как верифицировать webhook от Facebook?

Meta подписывает payload через X-Hub-Signature-256 (HMAC-SHA256 с App Secret). Верификация: hmac.new(app_secret, request.data, sha256).hexdigest() == sig_header. При GET-запросе на endpoint нужно вернуть hub.challenge — это верификация при регистрации webhook.

Нативная интеграция теряет все UTM или только часть?

Facebook Lead Ads форма не передаёт UTM-параметры через нативную интеграцию — она не знает о URL объявления. UTM из ad-параметров доступны через Graph API (campaign_id, adset_id, ad_id). Сам fbclid (click ID) не генерируется для Lead Ads — только для переходов на сайт.

Как работает Upsert в HubSpot API?

HubSpot v3 API не имеет прямого upsert endpoint для Contacts. Решение: сначала пробовать create -> при 409 (duplicate) -> поиск по email -> update существующего контакта. Альтернатива: использовать batch/upsert endpoint (доступен с Operations Hub).

Итого

  • Нативная интеграция: работает для простых форм, создаёт дубли, теряет UTM и кастомные поля
  • Прямая интеграция: Graph API webhook -> fetch lead -> upsert в HubSpot с campaign_id/adset_id/ad_id
  • Upsert: search by email -> update, чтобы не дублировать существующие контакты
  • Кастомные поля: явный маппинг из field_data в HubSpot Custom Properties
  • Атрибуция до закрытой сделки: нужна дополнительная система — например Prooflytics для multi-channel

Если вы используете HubSpot и Facebook Lead Ads и хотите настроить передачу UTM и кастомных полей — опишите структуру ваших форм. Exceltic.dev настроит прямую интеграцию через Graph API.

Ещё статьи

Все →