Apple Search Ads - рекламный канал App Store для привлечения пользователей через поиск. Для B2B SaaS с мобильным приложением это работает так: пользователь ищет «crm для продаж» в App Store, видит вашу рекламу, устанавливает приложение и через 2-3 недели становится платящим клиентом. Без атрибуции вы знаете только cost per install. С Prooflytics - стоимость закрытой B2B-сделки из App Store кампании с разбивкой по keywords и adGroups.
B2B-маркетологи недооценивают Apple Search Ads по простой причине: стандартные инструменты аналитики показывают только install rate и conversion to trial. Цепочка «keyword -> install -> trial -> qualified lead -> closed deal» обычно обрывается на стыке мобильного приложения и CRM. Именно этот разрыв закрывает интеграция Prooflytics с Apple Search Ads.
В этой статье разберём технологию атрибуции AdServices, как передать attributionToken в Prooflytics и увидеть стоимость закрытой сделки из каждой App Store кампании.
Почему стандартные инструменты не дают полной картины
Apple Search Ads предоставляет встроенную аналитику: impressions, taps (клики), installs, TTR, CR. На уровне кампании и keyword группы. Но здесь данные заканчиваются - дальше в CRM они не попадают.
После iOS 14.5 (ATT фреймворк, 2021) отслеживание через IDFA требует явного согласия пользователя. Большинство пользователей отказывают. Это означает что сторонние MMP (AppsFlyer, Adjust, Branch) работают с ограниченными данными.
Apple решила эту проблему собственным инструментом: AdServices Attribution API - privacy-preserving атрибуция, которая не требует IDFA. Работает через cryptographically-signed attributionToken, генерируемый на устройстве.
AdServices attribution - Apple-native механизм атрибуции: приложение запрашивает токен на устройстве сразу после установки, отправляет его на ваш сервер, сервер обменивает токен на данные кампании через Apple API. Токен не передаёт личные данные пользователя - только мета-данные кампании.
Техническая архитектура
iOS App
-> attributionToken() [AdServices framework]
-> POST /prooflytics/apple-attribution {token, user_id}
Prooflytics Backend
-> POST https://api-adservices.apple.com/api/v1/ {token}
<- {campaignId, adGroupId, keywordId, clickDate, countryOrRegion}
-> Сохранить attribution record (user_id -> campaign mapping)
CRM (HubSpot / Kommo)
-> Lead/Deal created (email или user_id)
<- Prooflytics находит attribution record по email
-> Записать источник: Apple Search Ads, campaignId, keyword
Когда сделка закрыта:
<- Prooflytics получает событие closed_won
-> Рассчитать CAC: campaign spend / closed deals
-> Показать в дашборде: keywords с наименьшим CAC
Реализация: iOS-часть
В iOS-приложении (Swift) при первом запуске запрашиваем attribution token:
import AdServices
func fetchAndSendAttributionToken(userId: String) {
guard #available(iOS 14.3, *) else { return }
do {
// Получаем токен атрибуции. TTL: 24 часа
let token = try AAAttribution.attributionToken()
// Отправляем в Prooflytics немедленно
sendToProoflytics(token: token, userId: userId)
} catch {
// Токен недоступен если пользователь не пришёл из рекламы
// Это нормально - просто нет данных атрибуции
print("No attribution token: \(error)")
}
}
func sendToProoflytics(token: String, userId: String) {
let url = URL(string: "https://api.prooflytics.io/v1/attribution/apple")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer YOUR_PROOFLYTICS_API_KEY", forHTTPHeaderField: "Authorization")
let body: [String: Any] = [
"token": token,
"user_id": userId,
"app_id": "your.bundle.identifier"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
URLSession.shared.dataTask(with: request).resume()
}
Вызывать fetchAndSendAttributionToken при первом запуске приложения после регистрации/входа - когда userId уже известен.
Реализация: серверная часть (Prooflytics)
import requests, time
from flask import Flask, request, jsonify
app = Flask(__name__)
APPLE_ATTRIBUTION_API = "https://api-adservices.apple.com/api/v1/"
@app.route("/v1/attribution/apple", methods=["POST"])
def receive_apple_attribution():
data = request.json
token = data.get("token", "")
user_id = data.get("user_id", "")
app_id = data.get("app_id", "")
if not token or not user_id:
return jsonify({"error": "missing fields"}), 400
# Обменять токен на данные кампании у Apple
attribution = exchange_token(token)
if not attribution:
return jsonify({"status": "no_attribution"}), 200
# Сохранить attribution record в БД
save_attribution(user_id, app_id, attribution)
return jsonify({"status": "ok"}), 200
def exchange_token(token: str) -> dict | None:
"""Exchange attribution token with Apple API. Token TTL: 24 hours."""
try:
r = requests.post(
APPLE_ATTRIBUTION_API,
json={"token": token},
headers={"Content-Type": "application/json"},
timeout=5
)
if r.status_code == 200:
data = r.json()
# attribution = None если пользователь не пришёл из рекламы
if data.get("attribution") is True:
return data
return None
except Exception:
return None
def save_attribution(user_id: str, app_id: str, data: dict):
"""
Пример данных attribution payload (с согласием ATT):
{
"attribution": true,
"orgId": 12345,
"campaignId": 678901,
"adGroupId": 234567,
"keywordId": 890123,
"adId": 456789,
"countryOrRegion": "US",
"conversionType": "download",
"clickDate": "2026-05-20T14:23:00Z"
}
"""
# Сохраняем в Prooflytics attribution store
# В реальной реализации - INSERT в PostgreSQL таблицу apple_attribution
record = {
"user_id": user_id,
"app_id": app_id,
"campaign_id": data.get("campaignId"),
"ad_group_id": data.get("adGroupId"),
"keyword_id": data.get("keywordId"),
"country": data.get("countryOrRegion"),
"click_date": data.get("clickDate"),
"conversion_type": data.get("conversionType"),
"org_id": data.get("orgId"),
"received_at": int(time.time()),
}
db.insert("apple_attribution", record)
Привязка attribution к CRM-сделке
Когда лид из мобильного приложения регистрируется в CRM (HubSpot или Kommo), Prooflytics ищет attribution record по user_id или email:
def enrich_lead_with_attribution(email: str, user_id: str) -> dict | None:
"""Find Apple Search Ads attribution for this user."""
record = db.query_one(
"SELECT * FROM apple_attribution WHERE user_id = %s ORDER BY received_at DESC LIMIT 1",
(user_id,)
)
if not record:
return None
# Получаем название campaign и keyword из Apple Ads API
campaign_name = get_campaign_name(record["org_id"], record["campaign_id"])
keyword_text = get_keyword_text(record["org_id"], record["keyword_id"])
return {
"source": "Apple Search Ads",
"campaign_id": record["campaign_id"],
"campaign_name": campaign_name,
"keyword": keyword_text,
"click_date": record["click_date"],
"country": record["country"],
}
Эти данные записываются в CRM как UTM-параметры или custom source properties - точно так же, как для Google Ads (через gclid) или Meta (через fbclid).
Что видит маркетолог в Prooflytics
После настройки в дашборде Prooflytics появляется:
- CAC по campaigns: «Кампания iPhone Users - US: $847 за закрытую сделку»
- CAC по keywords: «b2b crm app keyword: 3 сделки за месяц, $612 CAC»
- Time to deal: среднее время от установки до закрытия (например, 34 дня)
- Funnel by source: install -> trial -> qualified lead -> closed deal - по каждому ad group
Вместо «мы потратили $5000 на App Store и получили 200 установок» маркетолог видит «из 200 установок 12 дошли до paid plan, средний CAC $416, лучший keyword по CAC - “field service app”».
Реальный кейс
B2B SaaS для полевого сервиса: iOS-приложение, продажи enterprise через SDR-team. Apple Search Ads использовался как канал привлечения, но его эффективность оценивалась только по installs и trials.
После интеграции с Prooflytics:
- 4 месяца данных: $18 000 потрачено на Apple Search Ads, 840 установок
- Из 840 установок - 23 закрытых сделки (2.7% install-to-deal conversion)
- Средний CAC через App Store: $782 vs $1 240 через Google Ads
- Keyword «field service management app» - лучший CAC ($490), увеличили ставки на 40%
- Keyword «work order app» - 0 закрытых сделок за 4 месяца, отключили
Для кого актуально
B2B SaaS-компании, которые:
- Имеют iOS-приложение как основной или значимый канал онбординга
- Тратят на Apple Search Ads от $5 000/месяц
- Ведут B2B pipeline в HubSpot, Salesforce или Kommo
- Хотят видеть стоимость сделки, а не только стоимость установки
Актуально прежде всего для mobile-first B2B: field service, project management, logistics, sales enablement.
Аналогичный подход описан для других ad-каналов: Prooflytics + Google Ads, Prooflytics + Meta Ads. Apple Search Ads отличается механизмом атрибуции (device-level token вместо UTM/pixel), но логика замыкания на сделку идентична.
Часто задаваемые вопросы
Работает ли атрибуция без согласия ATT?
Да. AdServices Attribution API предоставляет два уровня данных: detailed (с согласием ATT) и limited (без согласия). В limited режиме доступны campaignId и adGroupId, но не keywordId и countryOrRegion. Для attribution на уровне кампании этого достаточно. Keyword-level доступен только с ATT consent.
Какой TTL у attributionToken?
24 часа с момента создания. Если не обменять токен за это время - он инвалидируется и данные теряются. Именно поэтому важно вызывать AAAttribution.attributionToken() и отправлять токен в Prooflytics немедленно при первом запуске, а не откладывать.
Нужно ли использовать MMP (AppsFlyer, Adjust) вместе с Prooflytics?
Одновременное использование возможно и дополняет картину. MMP закрывает Android-атрибуцию, cross-device, retargeting. Prooflytics использует AdServices для iOS-атрибуции и фокусируется на замыкании воронки на CRM-сделку - что MMP не делают. Для B2B SaaS с iOS-приложением достаточно Prooflytics без отдельного MMP.
Поддерживает ли Apple Search Ads attribution для подписок в App Store?
Да. conversionType в attribution payload может быть download или redownload. Для подписок через RevenueCat или StoreKit - атрибуция через AdServices работает аналогично: токен генерируется при установке, а событие подписки привязывается к attribution record через user_id.
Итог
Prooflytics + Apple Search Ads - атрибуция полного цикла для B2B мобильных приложений:
- iOS app:
AAAttribution.attributionToken()-> POST в Prooflytics - Backend: обмен токена на данные через Apple Attribution API
- Привязка attribution record к CRM-лиду / сделке по
user_idили email - При закрытии сделки: CAC = campaign spend / closed deals из App Store
- Дашборд: лучшие keywords по CAC, воронка install -> closed deal
Если ваша B2B SaaS имеет iOS-приложение и вы хотите видеть реальный CAC из Apple Search Ads - свяжитесь с командой Prooflytics для настройки интеграции.