How to integrate the Web Playable with your website-level login
Put your webgame on your website with your own website authentication.
This assumes you have already completed (or understand) the game-level authentication part, independent of this website-level authentication.
Before reading the how-to implementation guide, these two articles can give you an overview of how it works:
Article: Authentication for Game Developers
Article: Authentication for Headless Web Gaming Destinations
Summary of steps to integrate website-level user system with Pley.To start the game on the web:
- Call Pley's API
issue-access-tokenHTTP API to get an access token.- Initialize the Pley Web SDK on the website, including the callback to issue new Access Tokens.
- If the user is not logged in, initialize the Pley Web SDK without an access token to start a guest session.
- Create the playable with
new Pley.WebSdk(containerId, distributionId, options)(Read more).- Keep the playable session aligned with website login, logout, and account changes (see Update token).
- Implement a webhook e.g.
POST /allocate-game-userto let Pley know which Pley Game User ID to load for the session.- Create a new Pley Game User if it's a guest who hasn't played on web before.
(API Reference)
Terminology
| Term | Defintion |
|---|---|
| Scope | One or more games using the same authentication system, such as YourStudioID. |
| Scope User | A user on your website ('scope') |
| Game User | A user in the backend of one of the games |
| Pley Access Token | A token certifying ownership of a certain Scope User (alive for 30 minutes) |
| Pley Game User | Pley’s equivalent to your Game User for storing Pley-related features |
| Guest Session | A session where the user is not logged in, which is created by not issuing an access token. |
| Adopting progress | When a guest user signs up or logs in to an account without progress for a game, that scope user should be assigned the Pley game user. The user will continue to play with their progress, but in a logged-in state. |
Website setup
Issuing Pley Access Tokens
On your website, your account system is at the top level and determines which game progress is loaded when a user (Scope User) starts playing a game. To find the corresponding data on our side, Pley needs to stay in sync with which user is logged in. This is achieved by calling the Pley Issue Access Token endpoint using your Scope User ID and email (if available), which issues a Pley Access Token.
- The player clicks "Start Game".
- Call Pley's Issue Access Token endpoint and provide the user's ID and email.
- Receive Access Token in the response.
POST https://api.pley.com/v3/auth-kit/issue-access-token
// Authorization: Bearer API_TOKEN
// Body
{
// Scope ID for game manager
"scope_id": "xyz",
// An ID of one of your scope users
"scope_user_id": "xyz",
// Email of the user
"email": "[email protected]",
// (Optional) Omit if you are using pley guest user feature
"is_guest": false,
}
// Response
// 200
{
"data": {
// Pley Access Token
"access_token": "xyz"
}
}Pley Web SDK
For this workflow, create a Playable with external auth distribution channel and leave Basic iframe off. Its user storage base must match the scope used by your backend when issuing Pley Access Tokens. A standard Playable channel uses Pley authentication instead.
See Distribution Channels & the Smart Playable URL for channel configuration.
Adding Web SDK to your website
<script src="https://www.pley.com/playable/v1/web_sdk2.js"></script>
<div id="game-container" style="width: 100%; height: 80vh;"></div>Run your initialization after the SDK loads and the container exists. See Web SDK setup.
Web SDK Initialization with Initial Access Token
Pass the current player's Pley Access Token as initialToken, or undefined for a guest. Implement onIssueToken to request a fresh Pley Access Token from your backend when needed. Keep your Pley API token on the backend; it is not the player's access token and must not be embedded in browser code.
The following helper assumes your own backend exposes /api/pley/access-token and returns { "access_token": "..." }. Replace the endpoint and login-state helper with your implementation. It is not a Pley-hosted endpoint.
async function issueToken() {
if (!isLoggedIn()) return undefined; // Your website's current login state.
const response = await fetch("/api/pley/access-token", {
credentials: "same-origin",
});
if (!response.ok) throw new Error("Could not issue a Pley access token");
const data = await response.json();
return data.access_token;
}
// Run inside your application's asynchronous initialization flow.
const initialToken = await issueToken();
const playable = new Pley.WebSdk(
"game-container",
"YOUR_DISTRIBUTION_ID",
{
initialToken,
onIssueToken: issueToken,
}
);Also register onLoginRequested to connect the playable's login and signup requests to your website's login flow. The guest-only setup example cancels these requests with { cancelled: true }; replace that behavior for your production login integration.
Guest Sessions
For a guest session, omit initialToken and have onIssueToken return undefined while the website is logged out. Your backend's token-issuing handler should use the authenticated website session to determine the user, rather than trusting a user ID supplied by the browser.
Update token
Keep the playable aligned with website login, logout, and account switches. onIssueToken must always use the website's current authentication state.
Call updateToken on the existing playable when the user logs in, logs out, or switches accounts:
playable.updateToken(newAccessToken); // Login or account switch.
playable.updateToken(); // Logout and return to a guest session.The method returns nothing. When the user changes, the playable restarts the game for the new user. Returning undefined from onIssueToken does not clear an earlier token; explicitly call updateToken() on logout.
For login or signup requests from the game, implement onLoginRequested: update your website's auth state and call playable.updateToken(token) on success, then resolve { cancelled: false }. Resolve { cancelled: true } if the player closes the login UI. Register this handler alongside onIssueToken during construction; both are required for external-auth channels. See Web SDK setup.
Connecting website-level login with game progress
The Allocate Game User webhook lets Pley start the game as the correct Game User when they are logged (https://docs.pley.com/reference/allocate-game-user). The webhook takes care of a few use cases:
Handling the four authentication cases
The webhook implementation needs to follow this logic (in this order):
- Return existing web progress
If the Scope User already has aGame Userwith apley_game_user_id, return that ID.
Use case: The user is logged in and has prior progress on the web. - Return existing non-web progress
If the Scope User has a Game User but nopley_game_user_id, assignnew_pley_game_user_idto it and return that ID.
Use case: The user has prior progress but has never played on the web. - Adopt guest progress
If the above cases matched no game user, the user might be a guest and theunlinked_pley_game_user_idmay be set.
- Look up a Game User with the
pley_game_user_idmatchingunlinked_pley_game_user_id. - If not found, create a new Game User and assign
unlinked_pley_game_user_id. - In either case, assign
scope_user_idto the Game User and returnunlinked_pley_game_user_id.
Use case: The user played as a guest before logging in.
- Create new player
If no existing progress is found, create a new Game User with bothscope_user_idandnew_pley_game_user_id, then returnnew_pley_game_user_id.
Use case: The user is completely new to the game.
This is an example implementation with Typescript/Python of the webhook:
import { users } from './users'; // Mock user solution
interface AllocateGameUserRequest {
scope_user_id: string;
new_pley_game_user_id: string;
unlinked_pley_game_user_id?: string | null;
}
export function handleAllocateGameUser(req: AllocateGameUserRequest): string {
const { scope_user_id, new_pley_game_user_id, unlinked_pley_game_user_id } = req;
// Get existing user.
const existingUser = users.getByScopeUserId(scope_user_id);
if (existingUser) {
if (existingUser.pley_game_user_id) {
// 1. Existing web user
return existingUser.pley_game_user_id;
}
// 2. Existing non-web user
users.setPleyGameUserId(existingUser.id, new_pley_game_user_id);
return new_pley_game_user_id;
}
if (unlinked_pley_game_user_id) {
let guestUser = users.getByPleyGameUserId(unlinked_pley_game_user_id);
if (!guestUser) {
guestUser = users.createNewGameUser();
users.setPleyGameUserId(guestUser.id, unlinked_pley_game_user_id);
}
users.setScopeUserId(guestUser.id, scope_user_id);
// 3. Adopt guest progress
return unlinked_pley_game_user_id;
}
// 4. Brand new user
const newUser = users.createNewGameUser();
users.setPleyGameUserId(newUser.id, new_pley_game_user_id);
users.setScopeUserId(newUser.id, scope_user_id);
return new_pley_game_user_id;
}# This function takes the response as a JSON object and returns the Pley Game User ID
def handle_allocate_game_user(req):
existing_game_user = users.get_by_scope_user_id(req.scope_user_id)
if existing_game_user is not None:
if existing_game_user.pley_game_user_id is not None:
# 1. Existing web progress
return existing_game_user.pley_game_user_id
users.set_pley_game_user_id(existing_game_user.id, req.new_pley_game_user_id)
# 2. Existing non-web progress
return req.new_pley_game_user_id
if req.unlinked_pley_game_user_id is not None:
game_user = users.get_by_pley_game_user_id(req.unlinked_pley_game_user_id)
if game_user is None:
game_user = users.create_new_game_user()
users.set_pley_game_user_id(game_user.id, req.unlinked_pley_game_user_id)
users.set_scope_user_id(game_user.id, req.scope_user_id)
# 3. Adopt guest progress
return req.unlinked_pley_game_user_id
game_user = users.create_new_game_user()
users.set_pley_game_user_id(game_user.id, req.new_pley_game_user_id)
users.set_scope_user_id(game_user.id, req.scope_user_id)
# 4. New player
return req.new_pley_game_user_id
About the WebhookWebhook Info
Pley uses the 'Standard Webhook"-specification format.Webhook Cache
Webhook calls to Pley are cached for 24 hours, meaning Pley does not call the endpoint with the same parameter within 24 hours (caching happens for any 200 OK respose).Webhook Caching can be disabled in the Game Manager under Environment -> Webhook. This setting is per environment. Disabling caching in Development does not affect Production.
Article: Webhook HTTP API Rereferences
Updated about 2 hours ago

