Setup
There is nothing to install. When you upload, Habiv adds <script src="/sdk/habiv-bridge.js"> before your first script, so window.Habiv is ready before your own code runs.
On your own computer, or on any other website, window.Habiv is either missing or switched off (Habiv.enabled is false), and every call does nothing. Write calls as window.Habiv?.runStart() and you can leave them in everywhere.
The page around your game (title, description, how to play) isn't set through the SDK. Put it in a habiv.json next to your game and the publish form fills itself in.
Quick start
Most games only need these four calls:
// Habiv adds window.Habiv to your game when you upload it.
// On your own computer it's missing, so use ?. and keep the calls in.
const habiv = window.Habiv;
// 1. Everything has loaded and the game can be played.
habiv?.ready();
// 2. The player starts a round.
function startRound() {
habiv?.runStart();
}
// 3. The round is over.
function gameOver(score) {
habiv?.scoreSubmit({ value: score }); // leaderboard, if it's on
habiv?.runEnd({ outcome: "fail", score }); // "complete" if they won
}ready() is sent for you shortly after the page loads if you never call it. Call it yourself when a loading screen finishes, so Habiv knows exactly when your game can be played.
Runs
A run is one attempt: from pressing start to winning, losing or giving up. Runs are what the “runs” count on your game shows.
Without the SDK
Habiv works runs out for you. A run starts a moment after the player first clicks or presses a key inside your game, and ends as a “quit” when they leave the page or switch tabs. That gives you run counts and play time, but not wins, losses or scores.
With the SDK
As soon as your game calls runStart(), Habiv stops guessing and uses your calls for the rest of the visit. Call runStart() each time a round begins and runEnd() when it finishes:
habiv?.runStart(); // or runStart({ level: "1" })
habiv?.runEnd({
outcome: "complete", // "complete", "fail" or "quit"
score: 1840, // optional, a whole number
level: "3", // optional
progress_pct: 60, // optional, 0-100
});- Outcome.
"complete"means they won or finished,"fail"means they lost,"quit"means they gave up. Anything else counts as quit. - Your own end screen. Habiv draws nothing over your game when a run ends, so keep your game-over screen and its way to play again. A score sent with
scoreSubmitgoes on the leaderboard, and a new personal best in the top 3 gets a short note in the corner. - Starting again. Calling
runStart()while a run is going ends the old one as a quit first. - Timing is measured on Habiv's servers, not the player's device. Runs under half a second are flagged and left out of play-time stats.
Run counts refresh every few minutes. Plays on a draft and in the preview are never counted, so publish the game before you test counting.
Scores & leaderboards
First turn the leaderboard on: in the Details step when you publish, on the game's edit page in My games, or with update_game over MCP. Pick Highest wins for points or Lowest wins for times. Then send the score during a run:
habiv?.scoreSubmit({ value: 1840 });- Send it before
runEnd(). A score needs a run that's still going. - Whole numbers only. Round decimals first. For times, send milliseconds.
- One score per run. The first one counts. Each player keeps their best score on the daily, weekly and all-time boards.
- Cheat checks. Scores from runs shorter than 1 second are thrown out, and you can set a maximum number of points per second. Players who break the rules are flagged instead of ranked.
// For a "lowest wins" board, send the time in milliseconds as a whole number.
const ms = Math.round(performance.now() - startedAt);
habiv?.scoreSubmit({ value: ms });
habiv?.runEnd({ outcome: "complete", score: ms });Levels
Level calls feed the drop-off chart in your stats, so you can see which level players give up on. A level is any text up to 64 characters.
habiv?.levelStart({ level: "3" });
habiv?.levelComplete({ level: "3", score: 1200 });
habiv?.levelFail({ level: "3", score: 400 });
habiv?.beatGame(); // the player finished the whole gameSaves
Your game's own localStorage can be wiped between visits, because the game runs in an isolated frame. save and load keep data on Habiv's side instead, in the player's browser and separate for each game.
// Save any value that JSON can hold.
habiv?.save({ key: "progress", value: { level: 4, coins: 120 } });
// Load it back. You get null if nothing was saved.
const progress = (await habiv?.load({ key: "progress" })) ?? { level: 1, coins: 0 };load always resolves: with your value, with null if nothing was saved, or with null after 5 seconds if Habiv doesn't answer (for example on your own computer).
Pause, mute & player
The player page has Pause and Sound buttons. Listen for them so your game follows along:
habiv?.on("pause", () => game.pause());
habiv?.on("resume", () => game.resume());
habiv?.on("mute", (msg) => audio.setMuted(msg.on));
// Who is playing (null until Habiv has started the game)
const player = habiv?.player; // { id, handle, muted, locale }player.id is an anonymous ID for this browser. player.handle is the player's Habiv handle, or null if they aren't signed in. Games start muted, and the mute event tells you when that changes. Habiv.mode is "play" on the game page and "preview" in the publish wizard.
Other calls
habiv?.gameplayStart(); // real play begins (not menus or cutscenes)
habiv?.gameplayStop(); // back to a menu, paused, game over
habiv?.happytime(); // a great moment: Habiv shows a small "Nice!"
habiv?.design({ key: "picked_class", value: "mage" }); // your own stat
habiv?.error("Level file failed to load");design lets you track your own choices and events, up to 100 different keys per game, with a number, text or true/false value. Uncaught errors are reported for you, so error() is only for problems you catch yourself.
Poki, CrazyGames and Newgrounds
Already built for a game portal? Keep your code. Habiv swaps the Poki SDK v2, the CrazyGames SDK v2 and v3, and Newgrounds.io for local versions that talk to Habiv:
- Loading finished becomes
ready(), the first gameplay start becomesrunStart(), and happy time works as usual. - Ads never show. Ad breaks finish at once, and rewarded ads grant the reward.
- Newgrounds scoreboard posts become
scoreSubmit(), and medals are recorded as your own stats.
Testing
- Upload the build on the publish page. The preview in the Art step runs the SDK but records nothing.
- Publish it, open the game page and play a round.
- Open the browser console on the game page. SDK calls show up there as
postMessagetraffic from the game frame, and game errors are logged as[habiv] game error. - Check the runs count and your stats in My games after a few minutes.
Reference
| Call | What it does |
|---|---|
ready() | The game can be played. Sent automatically after load if you don't call it. |
runStart({ level? }) | Starts a run. Switches off automatic run counting for this visit. |
runEnd({ outcome, score?, level?, progress_pct? }) | Ends the run as complete, fail or quit. |
scoreSubmit({ value }) | Sends a whole-number score to the leaderboard. Once per run, before runEnd. |
levelStart / levelComplete / levelFail | Level progress: { level, score? }. Feeds the drop-off chart. |
beatGame() | The player finished the whole game. |
save({ key, value }) | Stores a JSON value for this game in the player's browser. |
load({ key }) | Promise of the saved value, or null. |
gameplayStart / gameplayStop | Marks active play versus menus. |
happytime() | Shows a small “Nice!” on the player page. |
design({ key, value? }) | Your own stat. Up to 100 keys. |
error(message) | Reports a problem you caught. |
on(type, fn) / off(type, fn) | Listen for pause, resume, mute or init. |
player | { id, handle, muted, locale }, or null before init. |
enabled | true only when running on Habiv. |
mode | "play" or "preview". |