Usage Stats
Usage Stats is a package in the Awaken Store that counts how a game is played (sessions, levels, errors and events of your own) and sends it to a server of yours. It is two scripts that send through the engine's outbox: no address is built in, and no third party is involved.
Install
- Open the Store panel, find Usage Stats and press Import. Two scripts arrive: the library Usage Stats and the behaviour Usage Stats Session.
- Add Usage Stats Session to one object in each scene (a scene load ends the old scene's scripts). Fill in its fields:
| Field | What it is |
|---|---|
| Endpoint | your server's address, https (http only to localhost while you make the game). Blank sends nothing. |
| App | your app's id, as in App Settings (com.studio.game) |
| Version, Build | the version and build number the stores know |
From then on it starts and ends sessions by itself, and records the engine's errors.
Telling it what happens
Import what you need by name from any script:
ts
import { levelStart, levelEnd, track, sessionProps } from "Usage Stats";
levelStart(55, { tier: "medium" }); // a level begins
levelEnd(55, "won", { hints: 1 }); // "won", "lost", or "abandoned" when the player leaves it
track("unlock", { step: "seen" }); // anything else
sessionProps(() => ({ maxLevel: 57, ownsUnlock: false })); // read as each session ends| Call | What it does |
|---|---|
levelStart(level, props?) | A level begins. The same level carried over from an earlier session goes on counting; another level still in progress ends as abandoned. |
levelEnd(level, outcome, props?) | One level event with its seconds (only the time the app was in front) and the props from both calls. |
track(name, props?) | Any other event. name: a letter, then letters, digits or _, at most 32. |
sessionProps(fn) | What every session's summary carries besides its length and age. |
on(hook, fn) | Hear launch, background, foreground, close, sessionStart, sessionEnd (with the summary) or error. A background hook runs before the session ends, so what it records goes with it. Returns the way to stop hearing it. |
flush() | Send what is recorded now. |
configure(config), attach(api), update(api) | What the session behaviour calls; call them yourself to run it from a script of your own. |
Props are flat: strings (cut to 2,000 characters), numbers, booleans and null, at most 32. Anything nested is dropped.
Sessions
A session starts when the game launches or comes back to the foreground, and ends when it goes to the background or after 30 minutes without input (the length counts up to the last input; the next input starts a new session). A level still in progress when a session ends is not abandoned: it is carried into the next session, across a closed app too (it is kept in the save), and abandoned only when your game says the player left it.
What is sent
One entry per session (more when a session holds over 200 events), through the outbox, which sends {"batch": [entry, ...]}:
json
{
"v": 1,
"install": "9b2f4c1e-6a7d-4f0b-8c3e-1d2a3b4c5d6e",
"app": "com.raiblin.crownquest",
"version": "1.0.0",
"build": 1,
"platform": "ios",
"device": "phone",
"channel": "release",
"events": [
{ "name": "app_launch", "at": "2026-10-21T08:15:00Z", "props": {} },
{ "name": "level", "at": "2026-10-21T08:16:03Z", "props": { "tier": "medium", "hints": 1, "level": 55, "outcome": "won", "secs": 63 } },
{ "name": "session", "at": "2026-10-21T08:15:00Z", "props": { "maxLevel": 57, "ownsUnlock": false, "secs": 412, "daysSinceInstall": 3 } },
{ "name": "app_background", "at": "2026-10-21T08:21:52Z", "props": {} }
]
}| Field | Values |
|---|---|
platform | ios or android in the mobile app, web in a browser. The server also takes macos, windows and linux, kept for desktop apps: the package's PLATFORMS type holds all six, and a game passes its own with configure({platform}). |
device | tablet when the view is at least 600 CSS px on its short side, else phone. |
channel | The engine's api.app.channel: release for players, beta for a TestFlight build, dev for your own runs (the editor's Play, a build run from Xcode or Android Studio, a page on localhost, an automated browser). Your server can count players apart from testing by it. configure({channel}) overrides it; an engine from before api.app sends no channel field. |
The events it records itself are app_launch, app_foreground, app_background, app_close (a web page closing mid-session), session, and error ({kind, message, stack}, at most 20 a session).
Privacy
- The install id is a random UUID made on the device and kept in the game's save. It is never the device's id, an account or a purchase receipt, and it is renewed every 13 months (a new UUID; the old one is no longer sent).
optOut()deletes the id, the level in progress and everything not yet sent (the outbox's queue for your endpoint too), and records nothing more untiloptIn(), which starts again with a new id.optedOut()says which.reset()makes a new id, as for a new player (a Reset everything button). It leaves a player who opted out opted out.
Give players a switch in your settings, and say what you collect in your privacy policy, App Store Connect's App Privacy (usage data, not linked to the person, not used for tracking) and Google Play's Data safety. Keep your server from storing IP addresses, and delete rows on a schedule.
See also
- Outbox & App Events - how entries are kept and sent, and the engine's events
- Scenes & Persistence - the save the install id is kept in