Docs
Everything you need to wire a game to Heartbeat. During the closed beta these docs describe the shipping design; endpoints go live for your account when you get a beta key.
Quickstart
Roblox
- Create your game in the dashboard and copy its key from the Analytics backend tab.
- Drop the Heartbeat ModuleScript into
ServerScriptService. - Enable Allow HTTP Requests in Game Settings, Security.
- Initialize from a server script:
local Heartbeat = require(script.Heartbeat)
Heartbeat:Init("hb_game_xxxx", "hb_secret_xxxx")
-- sessions, purchases, joins, errors: automatic
Heartbeat:Milestone(player, "tutorial_done")
Heartbeat:Event(player, "boss_attempt", 1, bossName)
Steam / C#
var hb = new HeartbeatClient("hb_game_xxxx", "hb_secret_xxxx");
hb.StartSession(SteamUser.GetSteamID().ToString());
hb.Milestone("tutorial_done");
hb.Purchase("supporter_pack", 4.99m);
REST ingest API
Any engine that can make an HTTPS POST can send events. Batch on your side (one request per server every few minutes), never one request per event.
POST https://api.gameheartbeat.dev/v1/events
Authorization: Bearer hb_secret_xxxx
Content-Type: application/json
{
"game": "hb_game_xxxx",
"server": "unique-server-id",
"seq": 12,
"sent": 1788000000,
"sessions": [
{"rowId": 410, "player": "76561198...", "joinedAt": 1787999000,
"leftAt": 1788000000, "durationSec": 1000, "isNew": 1,
"lastMilestone": "level_2", "purchases": 0, "revenue": 0}
],
"events": [
{"rowId": 411, "player": "76561198...", "type": "milestone",
"name": "tutorial_done", "value": 1, "ts": 1787999400}
]
}
Rules that keep your data trustworthy:
seqis per-server and only ever increases. A missing number is detected and shown as lost data instead of silently absorbed.rowIdis per-server and unique per row. Retrying a failed batch is always safe; duplicates are dropped on ingest.- Identify players by numeric platform id only. Requests containing usernames or emails in player fields are rejected.
Collection toggles
Every collection system can be switched off from the dashboard's Analytics backend tab. Your game polls its config about every five minutes, so a toggle takes effect without republishing. Sessions cannot be disabled, everything derives from them. Turning a system off stops future collection and never deletes what was already stored.
Custom metrics
Fire any event with one line, then define how it aggregates (count, sum, unique players) in the dashboard. Free accounts get 3 custom metrics, Pro unlimited.
How to read the numbers
- Completeness: batches received over batches expected, per hour. Below 100 means data was lost and the affected hours say so.
- Median vs average session: a big gap means AFK time. Idle share is also measured directly.
- Insufficient data: any rate computed over too few players renders as a state, not a number, so you never chase noise.
- Retention lag is physics: today's D1 is knowable tomorrow, D7 in a week. Blank means not yet knowable; zero means measured zero.