Skip to main content

Player

User identification

On the Jest platform, each user has a unique player ID per app. This identifier remains the same if a player starts as a guest and later registers, allowing you to track user progress and store user data.

Guest users can be prompted to register or sign in on the Jest platform. See Platform login for more information.

Registered users can be re-engaged via notifications. See Notifications for more information.

Get the player

Read the current player's ID and whether they are registered.

JestSDK.getPlayer()

JestSDK.getPlayer(): {
playerId: string;
registered: boolean;
username: string | null;
avatarUrl: string | null;
};

Example:

const player = JestSDK.getPlayer();
if (!player.registered) {
// Guest player: notifications cannot be scheduled
// Consider prompting the player to register
} else {
JestSDK.notifications.scheduleNotification({
/*...*/
});
}

Get a signed player payload

If your app has a backend, use this method to obtain a signed payload that can be sent to your server to authenticate the user and attach to authenticated requests.

This works for both registered users and guests. For guests, registered is false.

JestSDK.getPlayerSigned()

JestSDK.getPlayerSigned(): Promise<{
player: {
playerId: string;
registered: boolean;
username: string | null;
avatarUrl: string | null;
};
playerSigned: string; // JWS with the same `player` object plus iat, aud, sub
}>;

The returned playerSigned value is a JSON Web Signature (JWS) signed using your app’s shared secret with the HS-256 algorithm. You can use any standard JWS/JWT library on your backend to verify the signature and extract the user information.

The shared secret shown in the Developer Console is base64-encoded. Most JWT libraries expect the decoded key when verifying the signature.

The signed payload includes an issued-at (iat) timestamp that can be used to verify token freshness. Jest does not set an explicit expiration time; you may reject tokens older than a chosen threshold and have the client request a new token.

The verified payload has this shape:

type PlayerSignedPayload = {
player: {
playerId: string;
registered: boolean;
username: string | null;
avatarUrl: string | null;
};
iat: number;
aud: string; // game id
sub: string; // player id
};

Examples for popular backend languages, including signature validation and freshness checks (for example, rejecting tokens older than 24 hours), are provided below.

Example server code
// npm i jsonwebtoken
import jwt from "jsonwebtoken";

export function verifyPlayerSigned(token: string) {
const secretBase64 = process.env.JWS_SECRET!;
const secret = Buffer.from(secretBase64, "base64");

try {
// IMPORTANT: lock the allowed algs
const payload = jwt.verify(token, secret, {
algorithms: ["HS256"],
}) as jwt.JwtPayload;
const iat = payload.iat as number;
const maxAgeSeconds = 24 * 60 * 60;
const nowSeconds = Math.floor(Date.now() / 1000);

if (nowSeconds - iat > maxAgeSeconds) {
throw new Error("Token too old");
}

const player = payload.player as
| {
playerId: string;
registered: boolean;
}
| undefined;

if (!player) {
throw new Error("Missing player payload");
}

console.log("playerId:", player.playerId);
console.log("registered:", player.registered);
return payload;
} catch (err) {
console.error("Invalid token:", err);
throw err;
}
}

User data

If your app does not have a backend, Jest provides a simple key-value store for per-user data.

User data is stored alongside the user record on the Jest platform and is persistent across sessions and devices. All values must be serializable to JSON.

note

User data is written directly from the app client and must not be used to store sensitive information or data that requires strong security guarantees.

note

User data is limited to 1 MB per app; if this limit is exceeded, further writes will fail until the stored data size is reduced.

Get all data

Returns a snapshot of all key-value data stored for the current user.

JestSDK.data.getAll()

JestSDK.data.getAll(): { [key: string]: unknown };

Example:

const playerData = JestSDK.data.getAll();
console.log("Player data:", playerData);

// This returns a snapshot; modifying it does not update stored data.
playerData.coins = 1000; // does not affect stored player data

Get a value

Returns the value stored for the given key in the user data.

JestSDK.data.get(key)

Returns undefined if the key does not exist.

JestSDK.data.get(key: string): unknown;

Example:

const coins = JestSDK.data.get("coins");
console.log("Player coins:", coins);

Set a value

Sets the value for the given key in the user data.

JestSDK.data.set(key, value)

JestSDK.data.set(key: string, value: unknown): void;

Example:

JestSDK.data.set("coins", 750);

JestSDK.data.set(data)

Batch form: merges the provided key-value pairs into the user data, setting multiple keys at once.

note

This method performs a shallow merge and does not replace existing data. To remove a key, use JestSDK.data.delete(key) or set its value to undefined.

JestSDK.data.set(data: { [key: string]: unknown }): void;

Example:

JestSDK.data.set({ coins: 500, level: 2 });

Delete a value

Deletes the given key from the user data.

JestSDK.data.delete(key)

JestSDK.data.delete(key: string): void;

Example:

JestSDK.data.delete("temporaryBoost");

Flush pending writes

Waits for the platform to acknowledge the user data written so far. Set and delete send their update as soon as they are called, unless an earlier update is still unacknowledged — in that case the SDK coalesces the queued changes into the next message. Flushing completes immediately when nothing is outstanding. The acknowledgement reports that the platform handled the update, not that it stored it: an update the platform rejects because another session advanced the user's state is acknowledged as well.

JestSDK.data.flush()

JestSDK.data.flush(): Promise<void>;

Example:

// Update some data.
JestSDK.data.set("score", 1500);

await JestSDK.data.flush();
console.log("Player data update acknowledged by the platform.");