Документация


Unity SDK

Официальный плагин SpyMagic для Unity. Ставится как обычный пакет (Asset Store / Package Manager), настраивается в Edit → Project Settings → SpyMagic и с первого кадра начинает отправлять события: очередь с сохранением между запусками, батчи, повторы при обрывах связи и типизированные методы под все встроенные события аналитики.
Требования
параметр значение
Unity 2021.3 LTS и новее (2022.3, 6000.x)
Платформы WebGL, Android, iOS, Windows / macOS / Linux Standalone
Зависимости нет (ни Newtonsoft.Json, ни других пакетов), только UnityEngine
Scripting backend Mono и IL2CPP
Размер ~10 файлов C#, один .jslib для WebGL
Скачать
com.spymagic.sdk-1.0.0.tgz — для Package Manager (Add package from tarball)

spymagic-unity-sdk-1.0.0.zip — исходники пакета, для Add package from disk или папки Packages
Публикация в Unity Asset Store в процессе. После публикации пакет можно будет добавить в проект прямо из окна Package Manager (My Assets) — ссылка появится здесь.
Установка
Вариант 1 — Package Manager, tarball (рекомендуем)
1
Скачайте com.spymagic.sdk-1.0.0.tgz и положите его рядом с проектом (например, в папку Packages/).
2
В Unity откройте Window → Package Manager, нажмите + → Add package from tarball... и выберите файл.
3
Пакет появится в списке как SpyMagic Analytics SDK. Во вкладке Samples можно импортировать примеры.
Вариант 2 — Package Manager, из папки
1
Распакуйте zip. Внутри одна папка com.spymagic.sdk.
2
+ → Add package from disk... и укажите com.spymagic.sdk/package.json. Либо просто скопируйте папку в Packages/ вашего проекта — Unity подхватит её как embedded package.
Вариант 3 — manifest.json
"dependencies": {
    "com.spymagic.sdk": "file:../Packages/com.spymagic.sdk",
    ...
}
Настройка
1
Откройте Edit → Project Settings → SpyMagic (или Tools → SpyMagic → Settings). При первом открытии плагин сам создаст ассет настроек Assets/Resources/SpyMagicSettings.asset.
2
Вставьте в поле Token ключ проекта. Ключ видит администратор компании в разделе Настройки → Игры, кнопка «показать» рядом с иконкой ключа.
3
Проверьте блок Platform: по умолчанию Android → Google Play (2), iOS → Apple Store (5), WebGL и десктоп → www (1). Если билд один и живёт на одной площадке — поставьте Platform Override. Если WebGL-билд выкладывается на несколько порталов, площадку лучше выставлять в рантайме через SpyMagicSDK.SetPlatform(...), см. таблицу ID платформ.
4
Остальное оставьте по умолчанию: Auto Init и Auto Send Init включены — SDK стартует до загрузки первой сцены и сразу шлёт init.
поле по умолчанию описание
Token—ключ проекта, уходит в заголовке Mig-Token
Endpointhttps://spymagic.pro/track/адрес трекера, менять не нужно
Timeout Seconds5таймаут одного HTTP-запроса
Batch Interval30раз в сколько секунд отправлять очередь. 0 — каждое событие отдельным запросом (не рекомендуем)
Max Batch Size30отправить сразу, когда в очереди накопилось столько событий. Пока sid ≤ 100 (начало сессии) — порог 10, чтобы первые минуты игрока были видны быстрее
Max Queue Size200предел офлайн-очереди, самые старые события выбрасываются
Persist Queueвклхранить неотправленное между запусками (PlayerPrefs)
Send Package Metaвклдобавлять к каждому батчу служебное событие package_send с числом событий
Auto Initвклинициализация до первой сцены. Выключите, если хотите вызывать SpyMagicSDK.Init() сами
Auto Send Initвклслать init при инициализации. На WebGL пропускается, если init уже отправила страница (см. раздел WebGL)
Track Focusвклсобытия focus_lost / focus_gain
Use Device Identifierвклна Android / iOS uuid считается как uuid v5 от SystemInfo.deviceUniqueIdentifier, переустановка не плодит нового игрока
Platform Override / Mappingсм. вышекакой platform_id слать
Debug Logвыклписать диагностику в консоль Unity
Disable In Editorвыклничего не слать из редактора
Как это работает
uuid. Определяется один раз и хранится в PlayerPrefs. На WebGL сначала берётся localStorage.uuid (его заводит наш JS-сниппет), на мобильных — uuid v5 от идентификатора устройства, иначе случайный uuid v4. Это тот же uuid, который описан в API.
sid. Каждому событию SDK присваивает порядковый номер внутри сессии и unix-время, поэтому сервер восстанавливает порядок даже при плохой связи.
Очередь и батчи. Событие попадает в очередь. Очередь уходит одним POST-запросом каждые Batch Interval секунд, при достижении Max Batch Size, при forceSend, а также при потере фокуса, паузе и выходе из приложения.
Повторы. Ответ 2xx — доставлено. Статус 0 (нет сети) или 5xx — события возвращаются в голову очереди и уйдут со следующим батчем. 4xx (неверный токен, битые данные) — батч выбрасывается, повтор бы не помог.
Персист. Неотправленное сохраняется раз в 2 секунды и при сворачивании; на следующем запуске хвост прошлой сессии уходит первым.
Тело запроса, которое формирует SDK (формат format = 1):
POST https://spymagic.pro/track/
Content-Type: application/json
Mig-Token: <token>

{
    "format": 1,
    "uuid": "b2ce6279-cb36-45a1-b26c-ad40d4004e44",
    "user_id": 10455,
    "platform": 2,
    "events": [
        {"sid": 0, "event": "init", "detail": {"platform": 2, "version": "1.4.0", "language": "ru", "device": {...}, "screen": {...}}, "time": 1757800000},
        {"sid": 1, "event": "loading", "detail": {"step": 1}, "time": 1757800001},
        {"sid": 2, "event": "hit", "detail": {"url": "lobby"}, "time": 1757800004},
        {"sid": 3, "event": "package_send", "detail": {"events_num": 3}, "time": 1757800030}
    ]
}
Идентификация игрока
Пока игрок анонимен, события идут только с uuid. Как только ваш сервер выдал числовой id аккаунта, сообщите об этом SDK — иначе не будет ни retention, ни когорт, ни платежей по игрокам.
метод когда вызывать
SpyMagicSDK.Register(long userId, string userName = null) один раз в жизни игрока — аккаунт только что создан. Считается установкой в дашбордах
SpyMagicSDK.Auth(long userId, Dictionary<string, object> extra = null) каждый последующий запуск, когда игрок вошёл в существующий аккаунт. SDK сам добавит платформу, версию, язык, устройство и install_id
SpyMagicSDK.Logout() игрок вышел из аккаунта; очередь сразу отправляется
SpyMagicSDK.UserSet(string key, object value) свойства профиля: name, mail, password (0/1), gender (0..2), sound и music (0..100) — см. Игроки
SpyMagicSDK.SetUserId(long userId) если id известен без Register/Auth (редко). Register и Auth вызывают его сами
user_id — целое число (в C# long). Если у вас строковые id, заведите числовой суррогат на сервере: аналитика хранит id как bigint.
Методы и события
Все методы статические, в пространстве имён SpyMagic, класс SpyMagicSDK. Каждый метод формирует событие с тем именем и detail, которые ждут дашборды; подробности по каждому событию — в разделе События.
метод событие для чего
Техника
SendInit(extra = null)initстарт сессии; вызывается автоматически. Руками — только если выключили Auto Send Init
Loading(int step, string state = null)loadingэтап загрузки билда 1..N, метрика time to interactive
Hit(string url, props = null)hitсмена сцены/экрана, уникальное имя сцены
Click(float x, float y, string scene)clickтепловые карты кликов
Error(string text)errorклиентская ошибка
HttpRequest(url, method, status, timeSeconds)http_requestзапросы к вашему серверу — отчёт по пингу и лагам
автоматическиfocus_lost / focus_gainсворачивание и возврат в игру (Track Focus)
Прогресс — описание
Levelup(int level)levelupуровень аккаунта
Tutorial(int step), TutorialComplete()tutorial, tutorial_completeворонка туториала
BattleResult(result, point, timeSeconds, location = 0, power = 0, isAuto = false, isSurrender = false)battle_resultитог боя: result 1/0/-1, point — номер уровня
LevelResult(...)level_resultто же для игр с уровнями
StoryPoint(int step)story_pointточки сюжета
NarrativeStart / NarrativeStep / NarrativeSkip / NarrativeFinishnarrative_*катсцены и нарратив
Dialogue(int id), DialogueSkip(int id, int step)dialogue, dialogue_skipдиалоги
Feature(string text)featureоткрытие фичи
Экономика — платежи, ресурсы
Resource(Dictionary<string, object>)resourceсрез ресурсов на руках: ключ — хэш ресурса, значение — количество
PurchaseInit(offerCode, priceCode, priceQuantity)purchase_initнажата кнопка покупки
PurchaseMethod(int method, offerCode = null)purchase_methodвыбор способа оплаты (только свой эквайринг)
Purchase(offerCode, priceCode, priceQuantity, extra = null)purchaseплатёж подтверждён стором/шлюзом. Очередь отправляется сразу
PurchaseCanceled(transaction), PurchaseError(error, transaction)purchase_canceled, purchase_errorотмена и ошибки оплаты
VirtualPurchase(offerId, offerRewards, priceCurrency, priceCode, priceQuantity)virtual_purchaseпокупка за внутриигровую валюту
Реклама — описание
RewardedInit(int sectionId = 0)rewarded_initзапрошен rewarded-блок, sectionId — плейсмент
RewardedReceived(int sectionId = 0)rewarded_receivedролик досмотрен
RewardedError(int sectionId = 0, string error = null)rewarded_errorсеть не отдала рекламу
A/B и прочее — эксперименты
Experiment(int experimentId, int groupId)experimentигрок попал в группу эксперимента. Эксперимент должен быть заведён в разделе
Social(string key, object value)socialсоциальные действия
Произвольные события
Track(string eventName, Dictionary<string, object> detail = null, bool forceSend = false)любоекастомное событие; detail может содержать вложенные словари и списки
Track(string eventName, string key, object value)любоекастомное событие с одним параметром
TrackNow(string eventName, detail = null)любоеотправить немедленно, минуя очередь (без повторов)
Управление
Init() / Init(SpyMagicSettings) / Init(string token, SpyMagicPlatform platform)—ручная инициализация, если Auto Init выключен
SetPlatform(SpyMagicPlatform) / SetPlatform(int)—сменить platform_id в рантайме (WebGL на разных порталах)
SetEnabled(bool)—жёсткий выключатель: песочница, QA-сборки
SetTrackEnabled(bool, string source = null)—мягкий выключатель, например по заголовку вашего сервера
Flush()—отправить очередь сейчас
OnLog (event)—диагностика: сбои доставки, переполнение очереди
Uuid, UserId, Platform, QueueLength, IsInitialized—текущее состояние
Пример
using System.Collections.Generic;
using SpyMagic;
using UnityEngine;

public class GameBootstrap : MonoBehaviour
{
    private void Start()
    {
        // init уже ушёл автоматически до загрузки сцены
        SpyMagicSDK.Loading(1);

        // ваш сервер вернул аккаунт
        Backend.SignIn(account =>
        {
            if (account.IsNew) SpyMagicSDK.Register(account.Id, account.Name);
            else SpyMagicSDK.Auth(account.Id);

            foreach (var exp in account.Experiments)
                SpyMagicSDK.Experiment(exp.Id, exp.Group);

            SpyMagicSDK.Loading(2);
            SpyMagicSDK.Hit("lobby");
        });
    }

    public void OnBattleFinished(bool isVictory, int level, int seconds, int power)
    {
        SpyMagicSDK.BattleResult(isVictory ? 1 : -1, level, seconds, location: 0, power: power);
        SpyMagicSDK.Hit(isVictory ? "win" : "defeat");
    }

    public void OnLevelup(int level, int gold, int gems)
    {
        SpyMagicSDK.Levelup(level);
        SpyMagicSDK.Resource(new Dictionary<string, object> { { "gold", gold }, { "gems", gems } });
    }

    public void OnBuyClicked(string offer, double price) => SpyMagicSDK.PurchaseInit(offer, "RUB", price);

    public void OnPaymentConfirmed(string offer, double price) => SpyMagicSDK.Purchase(offer, "RUB", price);

    public void OnBossUnlocked(int bossId)
    {
        SpyMagicSDK.Track("boss_unlocked", new Dictionary<string, object> { { "boss_id", bossId } });
    }
}
Тот же сценарий целиком лежит в пакете: Package Manager → SpyMagic Analytics SDK → Samples → Basic Integration.
WebGL
init со страницы. Для веб-игр важно отправить init ещё до того, как загрузился движок — так считается честная скорость загрузки билда. В пакете есть сэмпл WebGL Template Snippet: скрипт spymagic-init.js, который вставляется в index.html вашего WebGL-шаблона перед загрузчиком Unity. Он генерирует uuid, кладёт его в localStorage, шлёт init и выставляет флаг window.spymagic.init_sent. SDK внутри билда подхватывает тот же uuid и второй init не отправляет.
Кросс-игровая кука. Запрос со страницы идёт с credentials: "include", поэтому аналитика может поставить общую куку mig_uid. Из UnityWebRequest такое невозможно, так что без сниппета кросс-игровое сопоставление игроков работать не будет.
Платформа. Один и тот же WebGL-билд может стоять на Яндекс.Играх, VK, CrazyGames. Определите портал (по домену, наличию YaGames / vkBridge / CrazyGames SDK) и вызовите SpyMagicSDK.SetPlatform(SpyMagicPlatform.YandexGames) как можно раньше. В сниппете для этого есть константа PLATFORM.
Блокировщики рекламы режут запросы к трекерам. SDK это переживает: события лягут в очередь и уйдут при следующем удачном флаше; после превышения Max Queue Size старые события отбрасываются.
<!-- index.html вашего WebGL-шаблона -->
<script>
    // содержимое Samples/WebGL/spymagic-init.js, TOKEN / VERSION / PLATFORM заменить на свои
</script>
<script src="Build/{{{ LOADER_FILENAME }}}"></script>
Диагностика
Включите Debug Log в настройках — в консоли Unity появятся записи об отправленных батчах, ошибках HTTP и выброшенных событиях.
В окне Project Settings → SpyMagic в play mode есть кнопка Send test event (событие sdk_test) и живое состояние: uuid, user_id, platform, размер очереди.
Подпишитесь на SpyMagicSDK.OnLog, чтобы завести сбои доставки в собственный логгер. Отчётов не больше 20 за сессию, переполнение очереди репортится с прореживанием 1, 10, 100.
Проверить, что события доехали, можно в разделе События проекта — батч уходит не позже чем через Batch Interval секунд (30 по умолчанию), либо вызовите SpyMagicSDK.Flush().
SpyMagicSDK.OnLog += (message, data) =>
    Debug.LogWarning("[SpyMagic] " + message + " " + SpyMagicJson.Serialize(data));
FAQ
SDK многопоточный? Нет. Все вызовы — из главного потока Unity. Из фоновых потоков прокидывайте через свой диспетчер.
Что положить в detail? Строки, числа, bool, enum (уйдёт числом), Dictionary<string, object>, списки и массивы, null. Остальное сериализуется через ToString(). Свой JSON-сериализатор внутри, Newtonsoft не нужен.
Как не слать данные из QA-сборок? SpyMagicSDK.SetEnabled(false) сразу после инициализации, либо флаг Disable In Editor для редактора. Лучший вариант — отдельный проект в аналитике с другим токеном для тестового окружения.
Игрок переустановил игру — это новый игрок? На Android / iOS с включённым Use Device Identifier uuid считается от идентификатора устройства, так что нет. На WebGL uuid живёт в localStorage браузера. Связка с аккаунтом в любом случае идёт через Register / Auth.
Сервер ответил 401 Неверный токен или проект удалён. Проверьте поле Token — ключ целиком, с префиксом до точки.
Нужна другая платформа, которой нет в enum SpyMagicSDK.SetPlatform(int) принимает любой id из таблицы платформ.
Нет ли Defold-версии? Есть: Unity SDK повторяет её протокол и поведение очереди один в один. Статус публикации — на странице Defold.