PLAY SDK
Every game running on PLAY gets window.PLAY automatically. There is nothing to install and no keys to manage: PLAY injects it into your game's page, and every call is answered by the PLAY page around your game. Your game never sees the player's PLAY account, email or cookies.
Building for PLAY for the first time? Start with the creator best practices.
Opened outside PLAY (for example from your own disk), window.PLAY still exists but its calls reject, so guard with try/catch and keep the game playable offline.
Player
const player = await PLAY.ready; // { playerId, name, signedIn, preview }playerId is stable for this player in your game and different in every other game, so players can't be tracked across games. Guests get an id too; when a guest signs in, their saves, achievements and scores move to their account (and they get their account's id from then on). Dashboard previews use a separate preview identity whose scores never appear on public leaderboards.
Cloud saves
await PLAY.storage.save({ level: 3, coins: 120 }); // slot "default"
await PLAY.storage.save("slot2", { level: 1 });
const data = await PLAY.storage.load(); // null if nothing saved
const slots = await PLAY.storage.list(); // [{ slot, bytes, updatedAt }]
await PLAY.storage.remove("slot2");Any JSON value. Up to 1 MB per slot, 20 slots and 5 MB in total per player per game.
Achievements
Define achievements on your game's Achievements and leaderboards page in the dashboard, or in a play.json file in your upload (below).
const r = await PLAY.achievements.unlock("first_win"); // { key, name, points, newlyUnlocked }
const all = await PLAY.achievements.list(); // hidden ones stay secret until unlockedLeaderboards
const r = await PLAY.leaderboards.submit("high_score", 4200); // { best, rank }
const top = await PLAY.leaderboards.top("high_score", 10); // { entries: [{ rank, name, score, me }], me }PLAY keeps each player's best score per board. Boards rank higher-is-better or lower-is-better (for times).
Game events and analytics
PLAY.game.started("classic"); // a run or level begins
PLAY.game.completed({ mode: "classic", score: 42 }); // a run or level is finished
PLAY.analytics.event("boss_defeated", { boss: "hydra", seconds: 93 });Completions feed your funnel in Analytics and help PLAY recommend your game. Event names use letters, numbers, - and _; props are flat strings, numbers or booleans, up to 2 KB.
Invites and lobbies
await PLAY.social.invite("Beat my score!"); // opens the share sheet with your game's link
const lobby = await PLAY.lobby.create({ maxPlayers: 4, state: { map: "forest" } });
// lobby.code is a 6-letter code friends type in
const joined = await PLAY.lobby.join("K7PQ2M");
await PLAY.lobby.setState(lobby.code, { map: "desert" }, lobby.version); // fails if someone changed it first
const now = await PLAY.lobby.get(lobby.code); // poll every second or two
await PLAY.lobby.leave(lobby.code);Lobbies are for matchmaking and small shared state (16 KB). They expire two hours after the last change. Real-time netcode is not part of the SDK yet.
Products and tips
const products = await PLAY.commerce.products(); // [{ sku, name, priceCents, type }]
const r = await PLAY.commerce.purchase("gold_pack"); // { purchased: true, sku } once the player confirms
const owned = await PLAY.commerce.entitlements(); // [{ sku, quantity }]
await PLAY.commerce.consume("gold_pack"); // for consumables
await PLAY.commerce.tip(); // the player picks an amountPurchases always open PLAY's own confirmation on the PLAY page, outside your game, so players know exactly what they are paying. Set up products in the dashboard under Monetization.
Pause, resume and mute
PLAY.on("pause", () => game.pause()); // the tab was hidden
PLAY.on("resume", () => game.resume());
PLAY.on("mute", (muted) => audio.setMuted(muted)); // PLAY also mutes Web Audio and media for youplay.json
Put this next to your index.html to create achievements and leaderboards when your build is processed:
{
"achievements": [
{ "key": "first_win", "name": "First win", "description": "Win a round.", "points": 10 },
{ "key": "secret", "name": "Found it", "points": 50, "hidden": true }
],
"leaderboards": [
{ "key": "high_score", "name": "High score", "order": "desc", "format": "number" },
{ "key": "speedrun", "name": "Fastest", "order": "asc", "format": "time_ms" }
]
}Errors and limits
Calls reject with an Error whose code is one of bad_request, not_found, quota, conflict, rate_limited, unauthorized or unavailable. Each play session can make 240 calls a minute, 60 of them writes.
Try it: upload the sdk-demo fixture, or start from a template in PLAY Studio.