TikTok: события приложения для рекламы
Шпаргалка: что и зачем настраивать в Expo-приложении, чтобы реклама в TikTok Ads видела установки, регистрации и покупки. Значения в примерах взяты из AiAstrology, в новом приложении подставь свои (таблица в самом конце). Соседние инструкции: Google, Meta.
Как всё связано
В отличие от Meta, у TikTok отдельный набор данных на каждую платформу: одно приложение для Android, другое для iOS, и у каждого свой TikTok App ID и App Secret. Наборы данных создаются прямо внутри рекламного аккаунта, поэтому отдельно связывать их с рекламой не нужно.
Кто есть кто
Чек-лист для нового приложения
Шаги по порядку. Галочки сохраняются только в этом браузере.
- Взять TikTok App ID и App Secret для каждой платформысекрет показывается один раз
- Пройти верификацию (Pending verification)нужны настоящие, не тестовые события
- Обновить данные о приватностидо релиза
1Events Manager
ads.tiktok.com → слева Assets → Events Manager.
2Наборы данных для Android и iOS
- Connect data source → App.
- iOS: App Store ID или ссылка на приложение. Android: Google Play, package name.
- Способ передачи событий: TikTok SDK (не Mobile Measurement Partner).
В AiAstrology получились два набора: AiAstrology (Android, com.kapernikrs.aiastrology) и AiAstrology Pro (iOS, 6756072533). У обоих сначала «Dataset created», а «Events received» появляется после подключения SDK.
3TikTok App ID и App Secret
У каждого набора данных: Continue setup → мастер SDK setup guide.
- 02 Install app code — пропустить (Next): там инструкция для нативного проекта (Maven / CocoaPods), а у нас SDK ставится через npm (шаг 4).
- 03 Initialize app — здесь TikTok App ID и App Secret. Секрет копировать кнопкой Copy App Secret, а не перепечатывать со скриншота: в шрифте не различить
lиI,Oи0.
.env.- 04 Implement event code — пропустить, события прописаны в коде (шаг 6). 05 Verify setup — закрыть.
На странице набора данных (Overview → Tracking Settings) должно стоять Preferred connection method: TikTok SDK.
4SDK и репозиторий jitpack
react-native-tiktok-business-sdk — обёртка над ними (около 114 тыс. скачиваний в месяц). Android-SDK TikTok лежит в репозитории jitpack, без него Gradle его не найдёт.yarn add react-native-tiktok-business-sdk
В AiAstrology стоит 1.7.1 (нативные SDK: iOS 1.7.1, Android 1.7.0). Плагина для Expo у пакета нет, поэтому репозиторий и правила ProGuard добавляются через expo-build-properties в app.json:
["expo-build-properties", {
"android": {
"extraMavenRepos": ["https://jitpack.io"],
"extraProguardRules": "-keep class com.tiktok.** { *; }\n-keep class com.android.installreferrer.** { *; }"
}
}]
Потом npx expo prebuild и пересборка. В Expo Go не работает.
5Ключи в .env
EXPO_PUBLIC_TIKTOK_ANDROID_APP_ID=7697183625745301511
EXPO_PUBLIC_TIKTOK_ANDROID_SECRET=…
EXPO_PUBLIC_TIKTOK_IOS_APP_ID=7598234769750605831
EXPO_PUBLIC_TIKTOK_IOS_SECRET=…
В src/constants/links.ts они собраны в TIKTOK вместе с App ID стора (storeId): package name для Android и App Store ID для iOS. Типы — в src/types/env.d.ts.
.env лежит в git; если репозиторий публичный, держать ключи в EAS-переменных окружения.6Запуск после ATT и отправка конверсий
В startAnalytics() (вызывается в App.tsx после ответа на ATT) — initTikTok(), в track() — reportTikTokEvent(name, attributes) рядом с AppMetrica, Firebase и Meta, при уходе в фон — flushTikTok().
src/services/analytics/tiktok.ts
import { Platform } from "react-native";
import {
TikTokBusiness,
TikTokContentEventContentsParameter,
TikTokContentEventName,
TikTokContentEventParameter,
TikTokEventName,
} from "react-native-tiktok-business-sdk";
import { TIKTOK } from "../../constants/links";
import { AnalyticsEvent } from "./events";
/**
* TikTok ads app events. Installs, launches and 2-day retention are logged by the SDK itself;
* only the conversions ads optimise for are sent, under TikTok's standard names.
*/
const config = Platform.OS === "ios" ? TIKTOK.ios : TIKTOK.android;
/** Debug mode makes events show up in Events Manager → Test event; on in dev builds or with EXPO_PUBLIC_TIKTOK_DEBUG=1. */
const debug = __DEV__ || process.env.EXPO_PUBLIC_TIKTOK_DEBUG === "1";
let isInitialized = false;
const warn = (what: string) => (e: unknown) => {
if (__DEV__) console.warn(`TikTok ${what} failed`, e);
};
/** Starts the SDK; called after the ATT answer, the SDK reads the tracking status itself. */
export const initTikTok = () => {
if (isInitialized || !config.appId || !config.secret) return;
isInitialized = true;
// Purchases are reported below with the plan's price, so the SDK's own purchase logging is off.
TikTokBusiness.initializeSdk(config.storeId, config.appId, config.secret, debug, { disablePaymentTracking: true }).catch(
(e: unknown) => {
isInitialized = false;
warn("init")(e);
},
);
};
export const reportTikTokEvent = (name: string, params: Record<string, string | number | boolean>) => {
if (!isInitialized) return;
if (name === AnalyticsEvent.OnboardingCompleted && !params.reentry) {
TikTokBusiness.trackEvent(TikTokEventName.REGISTRATION).catch(warn(name));
} else if (name === AnalyticsEvent.PurchaseResult && params.result === "purchased") {
const plan = String(params.plan);
const currency = String(params.currency);
if (Number(params.trial_days) > 0) {
TikTokBusiness.trackEvent(TikTokEventName.START_TRIAL, undefined, { currency, description: plan }).catch(warn(name));
} else if (typeof params.price === "number") {
TikTokBusiness.trackContentEvent(TikTokContentEventName.PURCHASE, {
[TikTokContentEventParameter.CURRENCY]: currency,
[TikTokContentEventParameter.VALUE]: params.price,
[TikTokContentEventParameter.CONTENT_TYPE]: "subscription",
[TikTokContentEventParameter.CONTENTS]: [
{
[TikTokContentEventContentsParameter.CONTENT_ID]: plan,
[TikTokContentEventContentsParameter.PRICE]: params.price,
[TikTokContentEventContentsParameter.QUANTITY]: 1,
},
],
}).catch(warn(name));
}
}
};
/** Sends buffered events now (e.g. when the app goes to the background and may be killed). */
export const flushTikTok = () => {
if (!isInitialized) return;
TikTokBusiness.flush().catch(() => undefined);
};
| Наше событие | В TikTok | Почему |
|---|---|---|
| установка, запуск, удержание на 2-й день | SDK шлёт сам | Install, Launch App, 2-Day Retention |
onboarding_completed (не повторный) | Registration | Стандартное событие «регистрация» |
| покупка плана с пробным периодом | StartTrial | Денег ещё не заплатили |
| покупка без пробного | Purchase с value и currency | Позволяет оптимизировать рекламу на выручку |
| автоматические покупки SDK | выключены | disablePaymentTracking: true, иначе покупки задвоятся |
| все остальные | не отправляются | Рекламе не нужны |
identify (имя, телефон, email) не вызываем. В TikTok уходят только факты: событие, план, цена.7Test event
У набора данных вкладка Test event. Два способа:
- QR code — отсканировать приложением TikTok на тестовом телефоне. На эмуляторе и в симуляторе TikTok нет, так что не подходит.
- Manual debug mode — включить режим отладки в SDK. В AiAstrology он включён в dev-сборках, а Release можно собрать с ним так:
EXPO_PUBLIC_TIKTOK_DEBUG=1 ./gradlew app:assembleRelease # android/ EXPO_PUBLIC_TIKTOK_DEBUG=1 xcodebuild … -configuration Release # ios/
Как должно выглядеть: в Event Activity через 15–30 секунд после запуска приходят Install и Launch App. Время показано по UTC.
В логе Android (adb logcat | grep TTSDK) в режиме отладки будет «Failed to flush N events, will discard them» — это нормально: в debug mode SDK всегда так помечает отправленные события, они идут только в Test event. На iOS (xcrun simctl spawn booted log show … | grep TikTok) — «TikTok SDK Initialized Successfully!» и ответ "code":0,"message":"OK".
8Верификация
По справке TikTok, верификация завершается, когда приходят события SDK, кроме событий в тестовом режиме. Каждая платформа проверяется отдельно. Достаточно запустить обычную сборку (без EXPO_PUBLIC_TIKTOK_DEBUG) на любом устройстве, или дождаться релиза.
9iOS: SKAN
Набор данных iOS → Overview → Configure SKAN: задать приоритет событий — покупка → пробный период → регистрация. Настраивать после того, как события начнут приходить. SDK сам регистрирует приложение в SKAdNetwork (опция disableSKAdNetworkSupport не задана). Отдельный SKAdNetwork-идентификатор TikTok в Info.plist не добавлен: официального значения не нашли, уточнить в документации TikTok при настройке SKAN.
10Приватность
- App Store Connect → App Privacy и Google Play → Data safety: то же, что для Meta (Device ID для отслеживания и рекламы третьих лиц, история покупок). Если для Meta уже отмечено, новых пунктов не нужно.
- Политика конфиденциальности: назвать TikTok Business SDK рядом с Meta и Firebase.
11Выпустить версию
Реальные установки и конверсии пойдут только с версии, где есть SDK. Для старта оптимизировать кампанию на установки или регистрацию, на покупки — когда их наберётся достаточно.
Значения AiAstrology
| Что | Android | iOS |
|---|---|---|
| Набор данных | AiAstrology | AiAstrology Pro |
| App ID (стор) | com.kapernikrs.aiastrology | 6756072533 |
| TikTok App ID | 7697183625745301511 | 7598234769750605831 |
| App Secret | в .env: EXPO_PUBLIC_TIKTOK_ANDROID_SECRET / EXPO_PUBLIC_TIKTOK_IOS_SECRET | |
| Коммит | 65df22d TikTok app events for TikTok ads | |
Грабли, на которые уже наступали
| Симптом | Решение |
|---|---|
| Мастер TikTok предлагает Maven / CocoaPods-код | Пропустить: SDK ставит npm-пакет |
| App Secret со скриншота не работает | Копировать кнопкой Copy App Secret: l/I и O/0 в шрифте не различить |
| «Failed to flush N events, will discard them» в логе Android | Так SDK ведёт себя в режиме отладки, события при этом видны в Test event |
| Test event: QR-код не сканируется на эмуляторе | Использовать Manual debug mode (EXPO_PUBLIC_TIKTOK_DEBUG=1) |
| Pending verification не уходит после тестовых событий | Тестовые не засчитываются, нужна обычная сборка или релиз |
| iOS-события не уходят сразу | SDK отправляет пачками, при уходе приложения в фон наш код вызывает flushTikTok() |