|
| 1 | +# @imtbl/audience |
| 2 | + |
| 3 | +Player analytics for game studios on Immutable. Track events, identify players, and link identities across platforms — so you can build a complete picture of every player across web, social, and in-game surfaces. |
| 4 | + |
| 5 | +## Quick Start |
| 6 | + |
| 7 | +```ts |
| 8 | +import { Audience, AudienceEvent, IdentityProvider } from '@imtbl/audience'; |
| 9 | + |
| 10 | +const audience = new Audience({ publishableKey: 'pk_imx_...', environment: 'sandbox' }); |
| 11 | + |
| 12 | +audience.identify(IdentityProvider.Steam, '76561198012345'); |
| 13 | +audience.track(AudienceEvent.Purchase, { currency: 'USD', value: 9.99 }); |
| 14 | +``` |
| 15 | + |
| 16 | +That's it. Events are batched and sent automatically. |
| 17 | + |
| 18 | +## API |
| 19 | + |
| 20 | +### `new Audience(config)` |
| 21 | + |
| 22 | +| Option | Type | Required | Description | |
| 23 | +|---|---|---|---| |
| 24 | +| `publishableKey` | `string` | Yes | Publishable API key from [Immutable Hub](https://hub.immutable.com) | |
| 25 | +| `environment` | `'dev' \| 'sandbox' \| 'production'` | Yes | Immutable environment | |
| 26 | + |
| 27 | +### `audience.track(event, properties)` |
| 28 | + |
| 29 | +Record a predefined player event. TypeScript enforces correct properties per event. |
| 30 | + |
| 31 | +```ts |
| 32 | +audience.track(AudienceEvent.LevelReached, { level: 10, characterClass: 'mage' }); |
| 33 | +audience.track(AudienceEvent.Spend, { currency: 'GOLD', value: 500, itemName: 'Sword of Fire' }); |
| 34 | +``` |
| 35 | + |
| 36 | +### `audience.identify(provider, uid, traits?)` |
| 37 | + |
| 38 | +Tell us **who** this player is. All subsequent `track()` calls are associated with this user. |
| 39 | + |
| 40 | +```ts |
| 41 | +audience.identify(IdentityProvider.Passport, 'abc-123', { email: 'player@example.com' }); |
| 42 | +audience.identify(IdentityProvider.Steam, '76561198012345'); |
| 43 | +``` |
| 44 | + |
| 45 | +Call `identify()` when the player logs in or you first learn who they are. |
| 46 | + |
| 47 | +### `audience.alias(from, to)` |
| 48 | + |
| 49 | +Link two identities so they are merged into one player profile. |
| 50 | + |
| 51 | +```ts |
| 52 | +audience.alias( |
| 53 | + { provider: IdentityProvider.Steam, uid: '76561198012345' }, |
| 54 | + { provider: IdentityProvider.Passport, uid: 'abc-123' }, |
| 55 | +); |
| 56 | +``` |
| 57 | + |
| 58 | +### `audience.reset()` |
| 59 | + |
| 60 | +Clear the current identity. Call on logout. |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## Supported Identity Providers |
| 65 | + |
| 66 | +| Provider | Enum | Example uid | |
| 67 | +|---|---|---| |
| 68 | +| Immutable Passport | `IdentityProvider.Passport` | `'abc-123-uuid'` | |
| 69 | +| Steam | `IdentityProvider.Steam` | `'76561198012345'` | |
| 70 | +| Epic Games | `IdentityProvider.Epic` | `'epic-account-id'` | |
| 71 | +| PlayStation | `IdentityProvider.PlayStation` | `'psn-account-id'` | |
| 72 | +| Xbox | `IdentityProvider.Xbox` | `'xbox-user-id'` | |
| 73 | +| Nintendo | `IdentityProvider.Nintendo` | `'nintendo-account-id'` | |
| 74 | +| Google | `IdentityProvider.Google` | `'google-uid'` | |
| 75 | +| Apple | `IdentityProvider.Apple` | `'apple-uid'` | |
| 76 | +| Discord | `IdentityProvider.Discord` | `'discord-user-id'` | |
| 77 | +| Email | `IdentityProvider.Email` | `'player@example.com'` | |
| 78 | +| Custom | `IdentityProvider.Custom` | any string — use when no other provider fits | |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +## Identity: `identify` vs `alias` |
| 83 | + |
| 84 | +| Method | What it does | |
| 85 | +|---|---| |
| 86 | +| `identify(provider, uid)` | "The current player is **this person**" — call on every login | |
| 87 | +| `alias(from, to)` | "These two IDs are **the same person**" — call when you know both | |
| 88 | + |
| 89 | +### Decision tree |
| 90 | + |
| 91 | +``` |
| 92 | +Player logs in |
| 93 | + │ |
| 94 | + ├─ Does your game use Passport login? |
| 95 | + │ │ |
| 96 | + │ ├─ YES ─── identify(IdentityProvider.Passport, uid) |
| 97 | + │ │ │ |
| 98 | + │ │ └─ Player also has another platform ID (Steam, Epic, etc.)? |
| 99 | + │ │ │ |
| 100 | + │ │ ├─ YES ─── alias({ provider: Steam, uid }, { provider: Passport, uid }) |
| 101 | + │ │ └─ NO ─── done |
| 102 | + │ │ |
| 103 | + │ └─ NO ──── identify(IdentityProvider.Steam, uid) // or whichever provider |
| 104 | + │ └─ done |
| 105 | + │ |
| 106 | + └─ Player hasn't logged in yet? |
| 107 | + └─ Just call track() — when identify() is called later, |
| 108 | + prior anonymous activity is attributed to that player. |
| 109 | +``` |
| 110 | + |
| 111 | +### Example A: Game uses Passport + Steam |
| 112 | + |
| 113 | +```ts |
| 114 | +audience.identify(IdentityProvider.Passport, 'abc-123'); |
| 115 | +audience.track(AudienceEvent.SignIn, { method: 'passport' }); |
| 116 | + |
| 117 | +// Player connects Steam in settings |
| 118 | +audience.alias( |
| 119 | + { provider: IdentityProvider.Steam, uid: '76561198012345' }, |
| 120 | + { provider: IdentityProvider.Passport, uid: 'abc-123' }, |
| 121 | +); |
| 122 | +``` |
| 123 | + |
| 124 | +### Example B: Game uses Steam only (no Passport) |
| 125 | + |
| 126 | +```ts |
| 127 | +audience.identify(IdentityProvider.Steam, '76561198012345'); |
| 128 | +audience.track(AudienceEvent.SignIn, { method: 'steam' }); |
| 129 | + |
| 130 | +// That's it. No alias() needed. |
| 131 | +``` |
| 132 | + |
| 133 | +### Example C: Anonymous visitor → known player |
| 134 | + |
| 135 | +```ts |
| 136 | +// Before login — events are captured anonymously |
| 137 | +audience.track(AudienceEvent.WishlistAdd, { gameId: 'my-game', source: 'twitter' }); |
| 138 | + |
| 139 | +// Player signs up |
| 140 | +audience.identify(IdentityProvider.Passport, 'abc-123', { email: 'player@example.com' }); |
| 141 | +audience.track(AudienceEvent.SignUp, { method: 'passport' }); |
| 142 | +``` |
| 143 | + |
| 144 | +### TL;DR |
| 145 | + |
| 146 | +- **Always** call `identify()` on login with the appropriate `IdentityProvider`. |
| 147 | +- **Only** call `alias()` if your game knows two IDs for the same player. |
| 148 | +- If you only have one ID, you're done. |
| 149 | + |
| 150 | +--- |
| 151 | + |
| 152 | +## Predefined Events |
| 153 | + |
| 154 | +### Web / Distribution |
| 155 | + |
| 156 | +| Event | Required Properties | Optional Properties | |
| 157 | +|---|---|---| |
| 158 | +| `SignUp` | — | `method` | |
| 159 | +| `SignIn` | — | `method` | |
| 160 | +| `WishlistAdd` | `gameId` | `source` | |
| 161 | +| `WishlistRemove` | `gameId` | — | |
| 162 | +| `Purchase` | `currency`, `value` | `itemId`, `itemName`, `quantity` | |
| 163 | + |
| 164 | +### In-Game |
| 165 | + |
| 166 | +| Event | Required Properties | Optional Properties | |
| 167 | +|---|---|---| |
| 168 | +| `SessionStart` | — | `sessionId` | |
| 169 | +| `SessionEnd` | — | `sessionId`, `duration` (seconds) | |
| 170 | +| `LevelReached` | `level` | `characterClass` | |
| 171 | +| `Spend` | `currency`, `value` | `itemId`, `itemName` | |
| 172 | +| `TutorialComplete` | — | `stepNumber` | |
0 commit comments