Skip to content

Host ↔ iframe messaging

The iframe and your page communicate with window.postMessage. Every message is an object with a source and a type. The iframe only posts to the origin you pass as the parent URL param, and only accepts messages whose source identifies your host handshake.

Setup

const FRAME = document.querySelector('#lootbox-solutions-iframe');
window.addEventListener('message', (e) => {
if (e.origin !== 'https://{operator}.app.lootboxsolutions.com') return; // verify sender
if (e.data?.source !== 'lootbox-solutions') return;
handle(e.data);
});
// to send a command into the iframe:
function send(msg) {
FRAME.contentWindow.postMessage({ source: 'host', ...msg }, 'https://{operator}.app.lootboxsolutions.com');
}

iframe → host

Messages the iframe emits (source: 'lootbox-solutions'):

typePayloadMeaning
ready{}Game app mounted and listening. Safe to send commands.
wallet:balance-changed{ balanceMinor, balanceFetchedAt, currency }Balance moved; refresh your own balance UI.
play:auth-required{ boxId, priceMinor, currency }A guest tried to act; sign them in, then upgrade in place with authenticate (or re-launch).
session:authenticated{ playerExternalId }A guest session was upgraded in place after an authenticate command — now logged in, no reload.
play:insufficient-balance{ boxId, priceMinor, balanceMinor, currency }Player lacks funds; offer a top-up.
navigation:changed{ path, query }The player navigated; mirror it into your address bar / persist for refresh.
box:card-clicked{ boxId }A box card was tapped in the widget. Navigate the parent to that box’s page — don’t navigate inside the iframe.
box:card-purchase{ boxId }”Buy now” on a card. Navigate the parent to the box page and launch with autoOpen so the box is bought + played on arrival.
resize{ height }Content height changed; resize the iframe if you size to content.

host → iframe

Commands your page sends in (source: 'host'):

typePayloadEffect
authenticate{ launchToken }Upgrade a guest (or re-authenticate) in place — the game app exchanges the token and switches to the authenticated session without reloading the iframe. See Convert without a reload.
theme{ appearance: 'light' | 'dark' }Mirror your light/dark mode into the game app, no reload.
navigate{ path }Move the game app to a page (e.g. a box, inventory).
locale{ locale }Change language on the fly.
currency{ currency }Change display currency on the fly.

Example: keep the URL in sync

function handle(msg) {
switch (msg.type) {
case 'navigation:changed':
// reflect iframe location in the host URL so refresh/share works
history.replaceState(null, '', `#/boxes/${msg.query.boxId ?? ''}`);
sessionStorage.setItem('gc:where', JSON.stringify(msg));
break;
case 'wallet:balance-changed':
renderBalance(msg.balanceMinor, msg.currency);
break;
case 'play:auth-required':
promptSignIn().then(() => relaunchAt(msg.boxId));
break;
}
}

Security notes

  • Always check e.origin against your operator host and e.data.source.
  • Pass parent=<your-exact-origin> so the game app scopes its outbound messages to you; messages are never broadcast to *.
  • Your origin must also be in the allowed embedding origins, or the browser won’t load the frame at all.