GameSDK progression & social reference
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
GameSDK progression & social reference
This is the reference for the GameSDK methods that feed player progression (XP, levels, achievements) and social features (friends, profiles, the in-game leaderboard). For concepts, caps, how to declare achievements, and what players see, read XP, achievements & social first. For loading the SDK, ready(), start() and on(), see GameSDK core reference.
Common behaviour
These rules apply to every method on this page.
Runtimes. Available wherever
window.GameSDKis loaded: HTML5 games that include the SDK script, and runtimes whose hosted shell includes it for you (see How games run). Calls work only while your game is running inside the Cool GPT Games player. Opened any other way, the page doesn't answer, so every method resolves its timeout fallback. - Signed-in vs guest. The player's sign-in state decides what happens. Guests always get the "guest" result listed for each method. Games embedded on other websites run as guests (see Embedding & the score bridge). - Play session.awardXpandunlockAchievementcount only inside a live play session that has run for at least 30 seconds with at least 2 heartbeats. The session opens when your game callsGameSDK.start()(orGameSDK.replay.ready()). Without one, they resolve with the "nothing landed" result.Never rejects, always settles. No method on this page rejects its promise or throws, and every promise has a built-in timeout. Failures come back as resolved values: zeros, empty arrays,
unlocked: falsewith areason,status: "error".Message budget. The player page accepts at most 30 SDK messages per second from your game, across all methods. Extra messages are silently dropped, and a dropped request resolves its timeout fallback. - Replies are matched by request id. Each call gets the answer to its own request, so parallel and repeated calls are safe.
Method summary
Method | Resolves | Needs sign-in | Timeout / fallback |
|---|---|---|---|
|
| Yes (guests get 0) | 8 s → |
|
| Yes (guests: | 8 s → |
|
| No | 5 s → last known player info |
| returns | No | n/a |
|
| Yes (guests get | 6 s → |
|
| Yes (guests get | 6 s → |
|
| No | n/a |
|
| Only for | 6 s → |
GameSDK.awardXp(amount, reason?)
awardXp(amount: number, reason?: string): Promise<{
granted: number;
total: number;
level: number;
leveledUp: boolean;
}>Asks the platform to give the signed-in player XP for genuine gameplay. The platform decides how much actually lands.
Parameters
Name | Type | Required | Constraints |
|---|---|---|---|
| number | yes | Converted with |
| string | no | Converted with |
Resolved value
Field | Type | Meaning |
|---|---|---|
| number | XP that actually landed. |
| number | The player's lifetime XP after this grant. |
| number | The player's site-wide level after this grant. |
| boolean |
|
Caps applied, in order: 100 per award → diminishing returns max(0.15, 1 − xpFromThisGameToday / 500) → 200 per game per session → 500 per game per player per UTC day → 3,000 per player per UTC day across the whole site. Achievement, first-play and personal-best XP from your game count toward the session and per-game daily totals. See XP, achievements & social for a worked example.
Guests and failures
Situation | Resolves |
|---|---|
XP landed |
|
All caps reached, or a non-positive amount |
|
Guest |
|
No play session ( |
|
Session under 30 s / 2 heartbeats, ended, or flagged |
|
Rate-limited, invalid |
|
No answer within 8 s (for example, the request was dropped over 30 messages/s) |
|
<last known> is the player's level as last seen by the page or the SDK (from getPlayer() or an earlier awardXp answer), or 1 if it isn't known yet. In every "nothing landed" case except "caps reached", total is a placeholder 0, not the player's real total. Show total only when granted > 0. These placeholder answers never change the level the SDK remembers for getPlayer(). The SDK doesn't tell you why nothing landed.
Side effects
The
xpevent fires with the same object on every answer from the page, includinggranted: 0. It doesn't fire on the 8 s timeout.If
leveledUp, thelevelUpevent fires once with{ level }.The site shows a "+N XP" toast when
granted > 0, and a "Level N!" toast on level-up. The player also gets a site notification and 100 bonus coins per level gained.Every landed XP point also gives the player 1 coin (virtual currency).
Limits
120 requests per minute per player per game. Over the limit, it resolves as "nothing landed".
The caps above.
Upload checks reject ungated grants on load or in
setInterval, and flag grants in loops/timers and literal amounts of 10,000 or more for review.
Example
function onRoundWon(stars) {
GameSDK.awardXp(10 + stars * 10, "Round won").then(function (r) {
if (r.granted > 0) hud.flash("+" + r.granted + " XP");
if (r.leveledUp) hud.flash("Level " + r.level + "!");
});
}Pitfalls
It can take up to 8 s to resolve if the page doesn't answer. Don't block gameplay on it.
Grants in the first ~30 s after
start()return 0.reasonis visible to players, and over 120 characters the grant fails.
GameSDK.unlockAchievement(key)
unlockAchievement(key: string): Promise<{
key: string;
name: string | undefined;
alreadyHad: boolean;
unlocked: boolean;
reason?: string;
}>Unlocks one of your game's declared achievements for the signed-in player. It's safe to repeat: a player holds each achievement once. The XP reward is set by the achievement's tier (common 10, uncommon 25, rare 50, epic 100, legendary 200) and goes through the same caps as awardXp, including the 100-per-grant limit.
Parameters
Name | Type | Required | Constraints |
|---|---|---|---|
| string | yes | Converted with |
Achievements are declared in a version's gamification block (sent with the upload-init or versions request, or through the CLI, publisher SDK or MCP server) and become active when that version is approved. See XP, achievements & social.
Resolved value
Field | Type | Meaning |
|---|---|---|
| string | The key you passed. |
| string | undefined | The achievement's display name. Set when the key matched an active achievement for a signed-in player in a valid session. |
| boolean |
|
| boolean |
|
| string (optional) | Present only when neither |
Outcomes
Situation | Resolves | Toast |
|---|---|---|
New unlock |
| Achievement toast (plus level-up toast if one happened) |
Already unlocked |
| None |
Unknown or deactivated key |
| None |
Guest |
| One-time sign-in toast |
No play session ( |
| None |
Session under 30 s / 2 heartbeats |
| None |
Session ended or flagged |
| None |
Rate-limited |
| None |
Other API or network error |
| None |
No answer within 8 s (for example, the request was dropped over 30 messages/s) |
| None |
A new unlock is unlocked === true. Unlocking doesn't return the XP granted, but the levelUp event fires if the achievement's XP caused a level-up.
Side effects
The
achievementevent fires only whenunlockedistrue.The unlock appears on the player's account page and in their public-profile showcase, and counts toward the site's daily "earn an achievement" quests.
Limits
60 requests per minute per player per game.
At most 30 achievements per game.
A literal key in your code that the uploaded version doesn't declare gets the version rejected automatically. A version uploaded without a
gamificationblock keeps the game's current achievements, so their keys count as declared.
Example
function onLevelComplete(level, hitsTaken, timeSec) {
if (level === 1) GameSDK.unlockAchievement("first_clear");
if (hitsTaken === 0) {
GameSDK.unlockAchievement("untouchable").then(function (r) {
if (r.unlocked) showBadgePopup(r.name);
});
}
if (timeSec < 60) GameSDK.unlockAchievement("speedrunner");
}Pitfalls
It can take up to 8 s to resolve if the page doesn't answer. Don't block gameplay on it.
A version approved with a
gamificationblock replaces the game's achievement list: keys it leaves out are deactivated, and an emptyachievementslist deactivates them all. Unlocking a deactivated key resolvesreason: "unknown_achievement". A version without a block leaves the list unchanged.namecan be set when nothing unlocked (the player already had it). Checkunlockedto decide whether to celebrate.
GameSDK.getPlayer()
getPlayer(): Promise<{
signedIn: boolean;
level: number;
handle: string | null;
}>Returns who is playing: whether they're signed in, their site-wide level, and their handle.
Parameters
None.
Resolved value
Field | Type | Meaning |
|---|---|---|
| boolean | Whether the player is signed in to Cool GPT Games. |
| number | Site-wide level (1–999). Always |
| string | null | The player's handle (without |
Situation | Resolves |
|---|---|
Signed in |
|
Guest |
|
Signed in, but looking up progress or profile failed |
|
No answer within 5 s | The SDK's last known player info (see pitfalls) |
Side effects
The player event fires with the same object when the answer arrives.
Limits
None beyond the 30-messages-per-second budget. The page looks the player up once (two API requests) and then answers from memory. Parallel calls share that one lookup, and a failed lookup is retried on the next call.
Example
GameSDK.getPlayer().then(function (p) {
if (p.signedIn) {
title.textContent = "Welcome back" + (p.handle ? ", @" + p.handle : "") + "!";
levelBadge.textContent = "Lv " + p.level;
} else {
title.textContent = "Playing as guest: sign in to earn XP";
}
});Pitfalls
The 5 s fallback returns the SDK's last known info. Before any answer, that's the guest shape. Don't treat a fallback as definitive.
No display name, avatar, XP or title is exposed. The remembered
levelis kept current byawardXpanswers and level-ups, but call again (or listen tolevelUp) if you display it.
GameSDK.on(event, callback)
on(event: string, callback: (payload: any) => void): typeof GameSDKSubscribes to SDK events. Chainable. Exceptions thrown in your callback are caught and ignored. Events for this area:
Event | Payload | Fires |
|---|---|---|
|
| After every |
|
| Once per level, when |
|
| Only when an |
|
| When a |
|
| Only when |
GameSDK
.on("levelUp", function (e) { confetti(); showLevel(e.level); })
.on("achievement", function (a) { log("Unlocked " + a.name); });The full event list (pause, resume, ads and more) is in GameSDK core reference.
GameSDK.social.getFriends()
social.getFriends(): Promise<Array<{
handle: string;
displayName: string | null;
avatarUrl: string | null;
level: number;
}>>Returns the signed-in player's accepted friends, most recently added first.
Parameters
None.
Resolved value
An array of friend objects:
Field | Type | Meaning |
|---|---|---|
| string | Friend's handle. Use it with |
| string | null | Friend's display name, if set. |
| string | null | URL of the friend's avatar image, if any. |
| number | Friend's site-wide level. |
Pending requests (incoming or outgoing) aren't included. The list isn't paginated.
Situation | Resolves |
|---|---|
Signed in | Array (may be empty) |
Guest |
|
Network/API error |
|
No answer within 6 s |
|
Limits
None beyond the 30-messages-per-second budget.
Example
GameSDK.social.getFriends().then(function (friends) {
friendsPanel.innerHTML = "";
friends.forEach(function (f) {
var li = document.createElement("li");
li.textContent = (f.displayName || "@" + f.handle) + " · Lv " + f.level;
li.onclick = function () { GameSDK.social.viewProfile(f.handle); };
friendsPanel.appendChild(li);
});
});Pitfalls
An empty array can mean "guest", "no friends" or "error". Use
getPlayer()to show the right empty state.Display names come from players. Insert them with
textContent, neverinnerHTML.
GameSDK.social.addFriend(handle)
social.addFriend(handle: string): Promise<{
handle: string;
status: "outgoing" | "friends" | "self" | "error";
}>Sends a friend request from the signed-in player to handle. If handle had already sent this player a request, the two become friends immediately.
Parameters
Name | Type | Required | Constraints |
|---|---|---|---|
| string | yes | Converted with |
Resolved value
Field | Type | Meaning |
|---|---|---|
| string | The handle you passed. |
| string | One of the values below. |
| Meaning |
|---|---|
| A request is pending from this player to |
| They're friends: already, or just now because a reciprocal request was accepted. |
|
|
| Nothing happened. See causes below. |
Causes of "error": guest, invalid handle format, no such player, either player has blocked the other, over the per-load or hourly limit, network/API error, or no answer within 6 s.
Side effects
On
"outgoing", the other player gets a site notification (and possibly an email): "@you sent you a friend request".On a reciprocal accept, the original requester gets "@you accepted your friend request".
The site shows the player a toast: "Friend request sent to @handle" or "You're now friends with @handle".
Guests see the one-time sign-in toast.
The
friendAddedevent fires with the result only for"outgoing"and"friends".
Limits
Limit | Value | Past the limit |
|---|---|---|
Per game load | 8 requests (counted even when a request fails or targets yourself; invalid handles and guest calls aren't counted) |
|
Per player, site-wide | 30 per hour |
|
Example
addFriendBtn.onclick = function () {
addFriendBtn.disabled = true;
GameSDK.social.addFriend(row.handle).then(function (r) {
addFriendBtn.textContent =
r.status === "friends" ? "Friends ✓" :
r.status === "outgoing" ? "Requested" :
r.status === "self" ? "That's you" : "Try later";
addFriendBtn.disabled = r.status !== "error";
});
};Pitfalls
Call it only after the player explicitly asks. Never auto-friend.
Take handles from
getLeaderboard()/getFriends(). Typed handles often fail.The 8-per-load budget is shared by all your calls, including failed ones.
GameSDK.social.viewProfile(handle)
social.viewProfile(handle: string): voidOpens the public profile of handle (https://coolgptgames.com/u/<handle>) in a new browser tab. The profile shows level ring and title, XP, achievement count, achievement showcase, friends, published games, and add-friend / follow buttons.
Parameters
Name | Type | Required | Constraints |
|---|---|---|---|
| string | yes | 1–40 characters of |
Return value
undefined. There's no promise and no confirmation. If the handle doesn't exist, the tab shows a not-found profile.
Guests and limits
Works for guests. Counts toward the 30-messages-per-second budget.
Example
leaderboardRow.addEventListener("click", function () {
GameSDK.social.viewProfile(entry.handle);
});Pitfalls
Call it directly inside a click/tap handler. Browsers may block new tabs that aren't opened in response to user input.
Don't call it on load or on a timer.
GameSDK.social.getLeaderboard(scope?)
social.getLeaderboard(scope?: "global" | "friends"): Promise<Array<{
rank: number;
handle: string;
displayName: string | null;
avatarUrl: string | null;
level: number;
score: number;
}>>Returns your game's top scores so you can draw an in-game leaderboard with profile and add-friend actions. This page covers the social side. For how scores are submitted, validated and ranked, see Scores, leaderboards & anti-cheat.
Parameters
Name | Type | Required | Constraints |
|---|---|---|---|
| string | no |
|
Resolved value
Up to 50 rows, highest score first, each player's all-time best on the public board. rank starts at 1. avatarUrl is included even though some older examples leave it out.
Situation | Resolves |
|---|---|
| Array (anyone, including guests) |
| Array of the player plus friends who have a score |
|
|
Network/API error, or no answer within 6 s |
|
Weekly/monthly and verified-only boards aren't available through this method. See Scores, leaderboards & anti-cheat.
Example
GameSDK.social.getLeaderboard("friends").then(function (rows) {
rows.forEach(function (r) {
addRow("#" + r.rank, r.displayName || "@" + r.handle, r.score, {
onProfile: function () { GameSDK.social.viewProfile(r.handle); },
onAdd: function () { GameSDK.social.addFriend(r.handle); },
});
});
});Related
XP, achievements & social: concepts, caps, declaring achievements, what players see - GameSDK core reference