Iframe Protocol

Upside embeds approved games in an iframe and exchanges a small set of browser messages with that iframe. The protocol is intentionally narrow: parent-to-game messages provide player context, and game-to-parent messages request UI refreshes or parent-shell feedback.

Treat postMessage data as untrusted until event.origin matches an expected Upside origin. Never accept a player token from *, from localhost, or from another arbitrary site.

Parent To Game

Initial Context

When the game iframe is available, Upside sends a context object to the iframe's origin.

ts
type UpsideContextMessage = { balance: string; token: string; locale: string;};
FieldRequiredDescription
balanceYesEstimated WIN balance in atomic units. WIN uses 18 decimals.
tokenYesPlayer JWT. Forward it to your backend as Authorization: Bearer {token}.
localeYesCurrent locale. Upside also appends it to the iframe URL as ?locale=....

Locale Change

ts
type LocaleChangeMessage = { type: "localeChange"; locale: string;};

Use this to update copy, number formatting, and any localized game assets without forcing a full iframe reload.

Game To Parent

Ready

ts
window.parent.postMessage({ type: "ready" }, "https://upside.win");

Send this after your app has mounted and registered its message listener. Upside responds by sending the latest context snapshot.

Win Modal

ts
window.parent.postMessage( { type: "showWinModal", wins: "2000000000000000000", }, "https://upside.win",);

Opens the standard Upside win modal. The optional htmlContent field can customize modal body content.

Loss Modal

ts
window.parent.postMessage( { type: "showLossModal", loss: "1000000000000000000", }, "https://upside.win",);

Opens the standard Upside loss modal. Use this after the backend has settled the session with processPayout.

Custom Modal

ts
window.parent.postMessage( { type: "showCustomModal", htmlContent: "<p>Round complete</p>", }, "https://upside.win",);

htmlContent must be a string. Keep it generated from trusted server-rendered templates or safe static content.

Toast

ts
window.parent.postMessage( { type: "showToast", message: "Game saved", description: "You can resume this session later.", variant: "success", duration: 4000, }, "https://upside.win",);

Supported variant values are success, error, warning, and info. Unknown variants fall back to the default toast.

Refresh Requests

ts
window.parent.postMessage({ type: "refetchBalance" }, "https://upside.win");window.parent.postMessage({ type: "refreshMatchHistory" }, "https://upside.win");

Call these after settlement, not before. If a backend payout fails, show an error instead of asking the parent to refresh stale data.

Message Matrix

DirectionMessageRequired FieldsTypical Timing
Game -> parentreadytypeApp mounted and listener registered
Parent -> gamecontext snapshotbalance, token, localeInitial load, balance/token updates
Parent -> gamelocaleChangetype, localePlayer changes locale
Game -> parentshowWinModaltype, winsBackend settled a winning session
Game -> parentshowLossModaltype, lossBackend settled a losing session
Game -> parentshowCustomModaltype, htmlContentTrusted custom result or explainer
Game -> parentshowToasttype, messageNon-blocking status feedback
Game -> parentrefetchBalancetypeAfter placeBet or processPayout success
Game -> parentrefreshMatchHistorytypeAfter processPayout success

Safe Handler

ts
const UPSIDE_ORIGINS = new Set(["https://upside.win", "https://www.upside.win"]);window.addEventListener("message", event => { if (!UPSIDE_ORIGINS.has(event.origin)) return; const data = event.data ?? {}; if (typeof data.token === "string") { // Store the token only in memory and send it only to your backend. } if (data.type === "localeChange" && typeof data.locale === "string") { // Update translations and number formatting. }});

Common Mistakes

Do not use * when a message includes or requests authenticated player state. Send messages to https://upside.win and accept messages only from known Upside origins.

The player-facing result should follow backend settlement. If processPayout fails, show an error toast and retry or reconcile the session.

Client events can be modified. Treat the iframe as a display and input surface; final outcome generation and payout calculation belong on the backend.

htmlContent is powerful and should be reserved for trusted templates. Never pass player-submitted HTML directly into parent-shell modals.

Ask a question... ⌘I