← Все инструкции

TikTok: события приложения для рекламы

Шпаргалка: что и зачем настраивать в Expo-приложении, чтобы реклама в TikTok Ads видела установки, регистрации и покупки. Значения в примерах взяты из AiAstrology, в новом приложении подставь свои (таблица в самом конце). Соседние инструкции: Google, Meta.

Как всё связано

Приложение
→
TikTok Business SDK
→
Events Manager (набор данных)
→
Рекламный аккаунт TikTok Ads

В отличие от Meta, у TikTok отдельный набор данных на каждую платформу: одно приложение для Android, другое для iOS, и у каждого свой TikTok App ID и App Secret. Наборы данных создаются прямо внутри рекламного аккаунта, поэтому отдельно связывать их с рекламой не нужно.

Кто есть кто

TikTok Ads Managerads.tiktok.com: реклама, оплата, Events Manager.
Events ManagerAssets → Events Manager: наборы данных (datasets), тестовые события, SKAN.
App IDИдентификатор приложения в сторе: package name на Android, App Store ID на iOS.
TikTok App IDДлинное число, которое TikTok выдаёт набору данных. Подтверждает, что приложение ваше.
App SecretКлюч, с которым SDK отправляет события. TikTok его не хранит: сохранить сразу.
Pending verificationTikTok ждёт первых настоящих (не тестовых) событий от SDK.
Debug mode / Test eventРежим, в котором события видны во вкладке Test event, но не идут в статистику.
SKANSKAdNetwork: как TikTok считает конверсии на iOS у тех, кто отказал в отслеживании.

Чек-лист для нового приложения

Шаги по порядку. Галочки сохраняются только в этом браузере.

Часть 1. Кабинет TikTok
Зачем вообще. Реклама на установку приложения в TikTok учится на событиях: кто установил после просмотра, кто зарегистрировался, кто купил. Без SDK TikTok видит только клики и не может ни посчитать цену установки, ни найти похожих людей.

1Events Manager

Зачем: здесь живут наборы данных приложения, ключи для SDK и проверка событий.

ads.tiktok.com → слева Assets → Events Manager.

TikTok Ads Manager: Assets → Events Manager

2Наборы данных для Android и iOS

Зачем: TikTok привязывает события к конкретному приложению в сторе, у каждой платформы он свой.
  1. Connect data source → App.
  2. iOS: App Store ID или ссылка на приложение. Android: Google Play, package name.
  3. Способ передачи событий: TikTok SDK (не Mobile Measurement Partner).

В AiAstrology получились два набора: AiAstrology (Android, com.kapernikrs.aiastrology) и AiAstrology Pro (iOS, 6756072533). У обоих сначала «Dataset created», а «Events received» появляется после подключения SDK.

Events Manager: два набора данных, Android и iOS

3TikTok App ID и App Secret

Зачем: без них SDK не стартует. TikTok App ID подтверждает, что приложение ваше, App Secret разрешает отправлять события.

У каждого набора данных: Continue setup → мастер SDK setup guide.

Install app code: пропустить Initialize app для Android: TikTok App ID и App Secret Initialize app для iOS: свой TikTok App ID и App Secret
App Secret TikTok не хранит и больше не покажет. Сразу сохранить в менеджер паролей и в .env.

На странице набора данных (Overview → Tracking Settings) должно стоять Preferred connection method: TikTok SDK.

Overview набора данных: TikTok SDK, Configure SKAN
Часть 2. Код приложения

4SDK и репозиторий jitpack

Зачем: официального SDK для React Native у TikTok нет, только нативные iOS и Android. Пакет 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

Зачем: так же хранятся ключи AppMetrica и RevenueCat. Пока значения пустые, TikTok-трекинг выключен.
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.

App Secret всё равно попадает внутрь приложения, так устроены все SDK. Но TikTok считает его секретом: с ним можно слать события от вашего имени. В AiAstrology .env лежит в git; если репозиторий публичный, держать ключи в EAS-переменных окружения.

6Запуск после ATT и отправка конверсий

Зачем: на iOS события должны идти после ответа на запрос отслеживания (ATT). А реклама учится на конверсиях под стандартными именами TikTok, поэтому отправляем только их.

В 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 уходят только факты: событие, план, цена.
Часть 3. Проверка и верификация

7Test event

Зачем: убедиться, что SDK шлёт события, до того как платить за рекламу.

У набора данных вкладка Test event. Два способа:

Test event: ожидание событий

Как должно выглядеть: в Event Activity через 15–30 секунд после запуска приходят Install и Launch App. Время показано по UTC.

Test event: Install и Launch App пришли

В логе 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Верификация

Зачем: пока набор данных в статусе Pending verification, TikTok не даёт полноценно продвигать приложение. Верхняя красная плашка «generate a TikTok App ID to verify your ownership» про то же.
Плашка о верификации TikTok App ID

По справке TikTok, верификация завершается, когда приходят события SDK, кроме событий в тестовом режиме. Каждая платформа проверяется отдельно. Достаточно запустить обычную сборку (без EXPO_PUBLIC_TIKTOK_DEBUG) на любом устройстве, или дождаться релиза.

9iOS: SKAN

Зачем: большинство пользователей iOS отказывают в отслеживании. Для них TikTok видит конверсии только через SKAdNetwork и только по событиям из схемы SKAN.

Набор данных iOS → Overview → Configure SKAN: задать приоритет событий — покупка → пробный период → регистрация. Настраивать после того, как события начнут приходить. SDK сам регистрирует приложение в SKAdNetwork (опция disableSKAdNetworkSupport не задана). Отдельный SKAdNetwork-идентификатор TikTok в Info.plist не добавлен: официального значения не нашли, уточнить в документации TikTok при настройке SKAN.

10Приватность

Зачем: TikTok — ещё одна третья сторона, которая получает идентификатор устройства и события. Анкеты в сторах и политика должны это отражать.

11Выпустить версию

Реальные установки и конверсии пойдут только с версии, где есть SDK. Для старта оптимизировать кампанию на установки или регистрацию, на покупки — когда их наберётся достаточно.

Справочник

Значения AiAstrology

ЧтоAndroidiOS
Набор данныхAiAstrologyAiAstrology Pro
App ID (стор)com.kapernikrs.aiastrology6756072533
TikTok App ID76971836257453015117598234769750605831
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()