Prooflytics + The Trade Desk: атрибуция B2B-конверсий в независимом DSP

The Trade Desk (TTD) - крупнейший независимый DSP с 11% рыночной доли программатик-рынка. Для B2B-компаний, которые покупают programmatic-инвентарь через TTD, ключевая проблема - атрибуция: клик по баннеру и подписание контракта разделяют 30-180 дней. TTD не знает, что этот пользователь стал клиентом.

Prooflytics собирает цепочку атрибуции: рекламный клик (TDID из URL) -> лид -> CRM-контакт -> закрытая сделка. TTD Offline Conversions API принимает эти данные обратно - и алгоритмы TTD начинают оптимизировать кампании под реальные B2B-конверсии, а не под клики или form submissions.

The Trade Desk (TTD) - независимый demand-side platform, основан в 2009, торгуется на NASDAQ (TTD). Позиционируется как альтернатива Google DV360 без конфликта интересов: TTD не продаёт собственный рекламный инвентарь, только покупает чужой. Популярен у enterprise-рекламодателей и агентств.

B2B-атрибуция в programmatic: в чём сложность

Google Analytics и стандартные пиксели трекают конверсии в рамках одной сессии или с окном атрибуции 30-90 дней. B2B-цикл сделки - 3-12 месяцев. К моменту подписания контракта пользователь давно потерял cookie, сменил устройство и забыл про баннер.

Стандартная проблема: TTD-кампания показывает 0 конверсий при реальной выручке от programmatic-клиентов. Бюджет на TTD урезается, хотя на самом деле канал приносит лиды - просто их путь не виден.

Архитектура Prooflytics + TTD

Лендинг: клиент кликает TTD-баннер
  -> URL: https://your-site.com/demo?tdid={TDID}&utm_source=ttd
  -> Prooflytics захватывает TDID, сохраняет в cookie + CRM

CRM (Kommo / HubSpot): лид -> квалификация -> договор
  -> Сделка закрыта (Closed Won)

Prooflytics:
  -> Найти TDID по contactId
  -> POST TTD Offline Conversions API
     {tdid, unifiedId2, conversionTime, value, currency}

TTD:
  -> Обновить attribution для этого пользователя
  -> Оптимизировать кампании под closed deals

Захват TDID и UID2

import hashlib, re

def normalize_email(email: str) -> str:
    # UID2 требует нормализации: lowercase, trim, убрать aliases Gmail
    email = email.strip().lower()
    local, domain = email.split("@", 1)
    if domain in ("gmail.com", "googlemail.com"):
        local = local.split("+")[0].replace(".", "")
    return f"{local}@{domain}"

def email_to_uid2(email: str) -> str:
    normalized = normalize_email(email)
    return hashlib.sha256(normalized.encode()).hexdigest()

# Захват TDID из URL при первом визите
def extract_tdid(request_args: dict) -> str | None:
    return request_args.get("tdid") or request_args.get("ttdid")

# Пример Flask: сохранить в cookie и Kommo custom field
from flask import request as flask_request, make_response

@app.route("/landing")
def landing():
    tdid = extract_tdid(flask_request.args)
    resp = make_response("Landing page")
    if tdid:
        resp.set_cookie("ttd_tdid", tdid,
                        max_age=365*24*3600, samesite="Lax")
    return resp

Отправка конверсии в TTD

import requests, os
from datetime import datetime, timezone

TTD_API_KEY     = os.environ["TTD_API_KEY"]
TTD_ADVERTISER  = os.environ["TTD_ADVERTISER_ID"]
TTD_TRACKING_TAG = os.environ["TTD_TRACKING_TAG_ID"]
TTD_BASE        = "https://api.thetradedesk.com"
TTD_HDR         = {"TTD-Auth": TTD_API_KEY,
                   "Content-Type": "application/json"}

def send_ttd_conversion(tdid: str | None,
                         uid2: str | None,
                         deal_value: float,
                         deal_id: str,
                         currency: str = "USD"):
    if not tdid and not uid2:
        return None  # нечего отправлять

    conversion = {
        "trackingTagId": TTD_TRACKING_TAG,
        "conversionTime": datetime.now(timezone.utc).strftime(
            "%Y-%m-%dT%H:%M:%SZ"
        ),
        "orderid":  f"deal_{deal_id}",
        "value":    deal_value,
        "currency": currency,
        "type":     "purchase",
    }
    if tdid:
        conversion["tdid"] = tdid
    if uid2:
        conversion["unifiedId2"] = uid2

    r = requests.post(
        f"{TTD_BASE}/v3/thirdpartydata/postconversion"
        f"/advertiser/{TTD_ADVERTISER}",
        headers=TTD_HDR,
        json=[conversion],
    )
    r.raise_for_status()
    return r.json()

# Интеграция с Kommo webhook (Closed Won):
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
    data = request.json or {}
    for lead_data in data.get("leads", {}).get("status", []):
        lead_id    = lead_data.get("id")
        new_status = lead_data.get("status_id")
        if new_status != int(os.environ["KOMMO_CLOSED_WON_ID"]):
            continue

        # Получить данные сделки + контакт
        lead, contact = get_lead_contact(lead_id)
        amount = float(lead.get("price") or 0)
        email  = get_email(contact)

        # Получить TDID из кастомного поля Kommo
        tdid   = get_cf(lead, int(os.environ.get("CF_TTD_TDID", "0")))

        uid2   = email_to_uid2(email) if email else None

        if not tdid and not uid2:
            add_note(lead_id, "TTD: нет TDID и email - конверсия не отправлена.")
            continue

        result = send_ttd_conversion(
            tdid     = tdid or None,
            uid2     = uid2,
            deal_value = amount,
            deal_id    = str(lead_id),
        )
        add_note(
            lead_id,
            f"TTD offline conversion отправлена: {amount} USD. "
            f"TDID: {tdid or 'нет'}, UID2: {'хеш email' if uid2 else 'нет'}"
        )

    return jsonify({"status": "ok"}), 200

UID2 в B2B без opt-in

UID2 (Unified ID 2.0) - экосистема идентификации на основе email/phone hash. Для full UID2 integration нужен opt-in пользователя через UID2 Operator. В B2B с длинным циклом это нереалистично.

Практичный подход для B2B: отправлять unifiedId2 как SHA256-хеш нормализованного email. TTD принимает это как “first-party UID2” и использует для атрибуции в тех случаях, когда пользователь встречался с рекламой в среде, поддерживающей UID2. Это менее точно, чем full UID2, но значительно лучше, чем ничего.

TDID (The Trade Desk ID) - более надёжный сигнал: это cookie/device ID, установленный самим TTD при просмотре рекламы. Если вы захватываете TDID с кликового URL - это прямая связь пользователя с TTD-кампанией.

Lookback window и задержка конверсий

TTD принимает конверсии с conversionTime в прошлом - lookback window по умолчанию 90 дней. Для B2B с циклом 6-12 месяцев: попросите аккаунт-менеджера TTD расширить окно атрибуции до 365 дней через настройки advertiser. Это стандартная опция для enterprise B2B-рекламодателей.

Проверка получения конверсий

После отправки конверсий:

  1. TTD Advertiser Portal -> Reports -> Conversion Report
  2. Проверьте что конверсии с типом purchase появляются
  3. Сравните с количеством отправленных Closed Won сделок
  4. Расхождение более 10% - проверьте TDID (возможно пользователь не кликал с TTD-кампании)

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

B2B компании с $50k+ месячным programmatic-бюджетом в TTD, длинным sales-циклом (30+ дней) и потребностью оптимизировать кампании под реальные продажи. Особенно актуально для enterprise SaaS, финансовых сервисов и профессиональных услуг. Без offline conversions TTD оптимизирует под микроконверсии (form fills, page views), а не под revenue.

Другие атрибуционные интеграции: Prooflytics + DV360 (Google programmatic), Prooflytics + Quora Ads (B2B intent).

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

Как получить TTD API Key?

TTD-Auth API Key выдаётся через TTD Advertiser Portal -> Settings -> API Access. Для его получения может потребоваться запрос к TTD account manager. TTD API не полностью самообслуживаемый - для первичного доступа обычно нужно взаимодействие с командой TTD.

Что делать если TDID не захвачен (direct traffic, email click)?

Fallback - UID2 через email hash. Если есть email контакта в CRM - всегда отправляйте unifiedId2. TDID + UID2 = максимальная точность. Только UID2 - приемлемо для B2B. Ни TDID ни UID2 - конверсия не атрибутируется, TTD не узнает про закрытую сделку.

Работает ли TTD в EU с учётом GDPR?

TTD поддерживает GDPR через TCF 2.0 (Transparency and Consent Framework). UID2 в EU работает через TCF-согласие. Для B2B без публичного сайта с cookie banner - консультируйтесь с юристом перед использованием UID2. TDID из кликовых URL технически не требует отдельного согласия если он передаётся в рекламной ссылке.

Можно ли отправить конверсии за прошлые периоды?

Да, в рамках lookback window advertiser. Если у вас есть исторические данные о сделках с TDID - можно batch-отправить через тот же API с историческими conversionTime. TTD пересчитает атрибуцию ретроспективно. Это особенно ценно при первом запуске интеграции.

Итог

Prooflytics + The Trade Desk - B2B offline attribution в programmatic:

  • TTD API: TTD-Auth заголовок с API Key
  • TDID: захватить из ?tdid= URL при клике, хранить в CRM
  • UID2: SHA256(normalize_email(email)) как fallback без full opt-in
  • POST /v3/thirdpartydata/postconversion/advertiser/{id} при Closed Won
  • Lookback window до 365 дней для B2B через настройки advertiser
  • Результат: TTD кампании оптимизируются под реальные B2B-продажи

Если ваша команда использует The Trade Desk для B2B programmatic и хочет связать closed deals с кампаниями - опишите задачу команде Exceltic.dev.

Ещё статьи

Все →