Integrate a Unity game
The complete Unity path, top to bottom. Covering every platform in one document instead — that's the full guide.
1. Get a project key
Every install needs a key shaped ah_xxxxxxxx. Create one at /projects/new, or run ah projects list if the CLI is already authenticated. Do not invent a key and do not proceed without one — the SDKs disable themselves without a key.
One project covers every platform a single product ships on — website, mobile app, and game share the same key and land in the same dashboard. Use a separate project only for a separate product, so their stats stay clean.
2. Unity install
Add the UPM package to Packages/manifest.json (or Package Manager → Add package from git URL), pinned to a tag. Unity 2021.3+; pure C#, zero dependencies, no native plugins.
"com.brightmotion.agenthog": "https://github.com/AnniesAI/agenthog-unity.git?path=com.brightmotion.agenthog#v0.1.0"
Configure via a settings asset (no code): Assets → Create → AgentHog → Settings, saved as Assets/Resources/AgentHogSettings.asset with your host + key — the SDK initializes itself on startup. In a shared repo, commit that asset blank (SDK stays inert) and keep the real key in a gitignored Assets/Resources/AgentHogSettingsLocal.asset, which takes precedence. Or in code, once at startup:
AgentHog.Init(new AgentHogConfig {
Host = "http://agenthog.io",
ProjectKey = "ah_xxxxxxxx", // blank key or Enabled=false → every call is a safe no-op
});Automatic: sessions, scene loads as pageview: /scene-name, uGUI taps as click: <label>, per-screen time, device context, offline/crash carry-over. Not automatic: single-scene games should call AgentHog.Screen("/shop") on UI-panel changes, and gameplay (world-space objects, UI Toolkit) is instrumented with Capture:
AgentHog.Capture("level_complete", new Dictionary<string, object> { ["level"] = 12 });
AgentHog.Identify(traits: new Dictionary<string, object> { ["user_id"] = playerId });
AgentHog.Reset(); // sign-out: device becomes a new anonymous personGames rarely have emails — a stable user_id trait still stitches identity. Using Singular for install attribution? Its Internal BI postbacks deliver the full verdict (network, campaign, creative, adset) server-side: generate the postback URL in project settings and call SingularSDK.SetCustomUserId(…) in the game with your own user_id (also sent via Identify) or AgentHog.AnonId — see attribution postbacks, which also covers pointing Singular at the URL directly versus relaying a copy through your own backend. Full docs: github.com/AnniesAI/agenthog-unity.
3. Event naming is a contract
The CLI, funnels, and dashboard parse these exact shapes. Autocapture already emits them; match the style when you add your own.
pageview: /pricing click: Join the waitlist form_submit: waitlist input: email scroll: 75% leave: /pricing
- · Custom names are stored verbatim. Short, readable, stable —
checkout_completed, notevt_CHECKOUT_v2or a UUID. - · Keep varying values out of the name.
capture('plan_selected', { plan: 'pro' }), nevercapture('plan_selected_pro')— props are queryable with--by props.plan, names baked with values are not. - ·
identify(email)is what stitches a person across devices. Call it at sign-in and after sign-up. A bare id works but will not merge across devices. - · Never put secrets, tokens, or full PII blobs in props — anyone with dashboard access can read them.
4. Verify before reporting success
Compiling is not evidence. Load the site or run the app, click through a few screens, then confirm data arrived:
ah events --since 24h # fastest proof, if the CLI is authenticated ah digest # sessions, sources, and top events in one report
Otherwise check the dashboard. Expect a pageview: row within seconds — the web tracker flushes every 5s or 10 queued events; React Native, Unity, and Capacitor every 10s or 20 events. Unity editor Play mode sends real events too (registered prop platform: editor).
5. Feature flags & A/B tests
Create a flag with ah flags create checkout_cta --variants control:50,b:50, then read it — the SDK assigns the variant deterministically per user and records exposure automatically (one $exposure event, plus $ff/checkout_cta on every later event, so ah funnel signup --by flag:checkout_cta just works):
AgentHog.FlagsReady(() => { // ruleset cached after the first launch
string v = AgentHog.Flag("difficulty_curve"); // "control" | "b" | null
ApplyDifficulty(v == "b" ? Curve.Gentle : Curve.Classic); // null → code default
});
AgentHog.FlagOn("new_shop_ui"); // boolean flags → true/falseFull loop — experiments, results, verdict gates, rollout percentages, kill switch: Experiments.
6. When events are missing
Work through this before adding more instrumentation.
| Symptom | Cause |
|---|---|
| Nothing at all | The settings asset has a blank key (the intended committed default — the real key belongs in AgentHogSettingsLocal.asset), or Init never ran. Set debugLog and watch the Console for [AgentHog] lines |
Clicks named like click: BtnStart2 | The control has no Text/TMP child — autocapture fell back to the GameObject name. Add label text |
| Gameplay taps missing | Autocapture covers uGUI (Canvas) only — world objects and UI Toolkit need explicit Capture |
| Traffic looks inflated | You are looking at bots — aggregates exclude them by default, --all includes them |
7. After integrating
Two follow-ups worth offering:
- · Define a conversion goal so sessions get marked converted:
ah goals set signup "form_submit: waitlist" - · Give the agent the read surface — install the ah CLI and add an AgentHog section to
CLAUDE.mdso future sessions query analytics instead of guessing.