Docs
Send events from anywhere that can speak HTTPS. Read these in order if you're new; jump to a section if you came here looking for one specific thing.
Quickstart
Three steps:
- Sign up — free, no card. Your first app + API key are generated by the onboarding wizard.
- Drop the SDK (or a curl) into your build, point it at the app's key, and ship a single event.
- Watch it appear in the dashboard within seconds. From there, define a loop or wait for users.
One-shot from a terminal
curl -X POST https://owlsignal.dev/api/v1/events \
-H "Authorization: Bearer pk_PASTE_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"events":[{
"build_version":"0.1.0",
"session_id":"00000000-0000-0000-0000-000000000001",
"player_hash":"0123456789abcdef0123456789abcdef",
"ts":"2026-05-06T12:34:56Z",
"type":"session",
"name":"Session:Start"
}]}' Wire format
POST /api/v1/events with a JSON body containing an events array (1–100 events per batch). Every event has:
| Field | Type | Notes |
|---|---|---|
build_version | string | 1–64 chars. Free-form (e.g. 1.4.0). |
session_id | uuid | Stable per session. Same id ties events to one session row. |
player_hash | string | 32–64 chars. Anonymous device hash. No PII. |
ts | ISO 8601 | Client clock. Server stamps separately too. |
type | enum | One of progression, design, resource, error, session. |
name | string | 1–100 chars. Convention: Verb:Subject e.g. Start:Run, CTA:Clicked. |
value | number? | Optional numeric (duration, score, currency delta). |
dim01..dim03 | string? | Optional indexed dimensions (≤64 chars). Used in dashboards for grouping. |
data | object? | Free-form key/value (string|number|boolean|null). Top-level only. |
Response is always 200 with { accepted, rejected, errors }. Bad events in a batch are rejected
but never fail the whole request — the SDK should never block the game.
Event types
Pick the one that best matches the moment. Type is purely a categorization signal — the
dashboard groups things by it, but you can model nearly anything with design if unsure.
sessionSession:Start/Session:End. Used to compute session duration. The SDK auto-fires these — you almost never call them by hand.progression- Phase markers:
Start:Run,Complete:Tutorial,Fail:Boss. Used by funnels and the Run analytics view. design- Gameplay or UX signals that aren't pure phase markers:
FirstTime:Combo,CTA:Clicked,Friction:DeadEnd. Default for "interesting moment, not sure what to call it." resource- Soft-currency tracking. Convention:
Source:Goldwith positive value,Sink:Goldwith positive value (the verb encodes direction). error- Exceptions / critical issues. Powers the Errors page. Optional
data.message,data.stack,data.scene,data.signature— signature groups identical errors.
Web SDK (JS/TS)
Lives in sdks/web in the repo. Copy the src/ contents
into your project for now, or wait for the npm package release. Initialize once near the root of your
client bundle:
import { OwlsignalClient } from '@owlsignal/web';
OwlsignalClient.Initialize({
apiKey: 'pk_live_...',
buildVersion: '1.4.0',
// endpointUrl is optional — defaults to https://owlsignal.dev/api/v1/events
});
// Then anywhere a meaningful moment happens:
OwlsignalClient.TrackProgression('Complete:Tutorial');
OwlsignalClient.TrackDesign('CTA:Clicked', { dim01: 'pricing-pro' });
OwlsignalClient.TrackResource('Source:Coins', { value: 50 });
OwlsignalClient.TrackError('NullRef', { data: { stack: 'at foo.bar:12' } });
// Optional: identify the user (still anonymous — this is just a stable hash).
OwlsignalClient.IdentifyUser('user-abc');
// Optional: respect a user opt-out flag.
OwlsignalClient.SetOptOut(true);
Auto-events
Once initialized, the SDK fires a few events automatically:
Session:Starton first track call after init.Session:Endonpagehide(sent viafetch keepalive).
Events are batched (every 30s or 30 events, whichever first). 5xx responses retry with exponential backoff; 4xx drops the batch.
Unity SDK
Lives in sdks/unity in the repo, shape-equivalent to the web SDK (same OwlsignalClient.Initialize + Track* methods). The full quickstart and sample scene live in the SDK
README — clone the repo or open the package directly to integrate.
Authentication
Send the API key in the Authorization header:
Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxx
Each key is scoped to one app inside one tenant. Generate keys in Settings → API keys. We store only a hash — the raw key is shown once when you generate it. Lost keys can be revoked + regenerated; we can't recover the raw value.
Rate limits & tier behavior
If your tenant has exceeded its monthly events budget, ingest silently drops the batch and returns 200 with { accepted: 0, rejected: N, reason: "tier_limit" }. The SDK never
sees a 5xx for tier reasons; your game/app keeps working. The dashboard surfaces the cap; we
email at 80% and 100% of budget.
Server-side validation rejects bad events individually (the rest of the batch goes through). The response always lists which indexes were rejected and why.
Privacy & opt-out
Events carry an anonymous player_hash only — no email, no IP, no real
identity. Opt-out is a client-side contract: when the user toggles "telemetry off", call OwlsignalClient.SetOptOut(true) (web) or the Unity equivalent. The SDK then drops events at the source — the server can't detect opt-out
because there's no identity to recognize.
Data residency: Postgres in eu-central-1 (Frankfurt), functions in fra1 (Frankfurt). See privacy for the full posture.