Embedding & the score bridge
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Embedding & the score bridge
Any published game on Cool GPT Games can be embedded on another website with an <iframe>. The embedded player is the real game with the site chrome removed: no header, no footer, just the game and a small "Powered by Cool GPT Games" link. It can also tell the page hosting it about scores and game events through postMessage, the score bridge, so your site can react to play, for example with its own leaderboard or a "play again" button.
This guide covers the embed snippet, what does and doesn't work inside an embed, the bridge messages, and how to handle them securely.
The embed URL
https://coolgptgames.com/embed/<slug><slug> is the game's slug, the last part of its page URL https://coolgptgames.com/game/<slug>. Every game page has a Share → Embed option that gives you a ready-made snippet.
The snippet
This is the snippet the game page gives you:
<iframe
src="https://coolgptgames.com/embed/space-miner-3fa2c1"
width="800"
height="600"
style="border:0;max-width:100%"
allow="fullscreen; autoplay; gamepad"
allowfullscreen
></iframe>Attribute | Why |
|---|---|
| The embed URL for the game |
| Any size you like. The game fills the frame. Pick a size that suits the game's aspect ratio. |
| No border, and the frame shrinks on narrow screens |
| Passes these browser permissions through to the game. Without them the game's fullscreen button, audio autoplay and gamepad support won't work in the embed. |
| Older-browser equivalent of |
For a responsive embed that keeps its aspect ratio:
<div style="position:relative;width:100%;aspect-ratio:4/3">
<iframe
src="https://coolgptgames.com/embed/space-miner-3fa2c1"
style="position:absolute;inset:0;width:100%;height:100%;border:0"
allow="fullscreen; autoplay; gamepad"
allowfullscreen
></iframe>
</div>There are no query-string options for the embed URL. Size, placement and permissions are all controlled by your <iframe>.
Requirements for the host page
Serve your page over HTTPS. The game inside the embed may only be framed by
https:pages, so on a plainhttp:page the embed shell loads but the game itself is blocked by the browser.The game must be published and allow embedding. Otherwise the embed shows a message instead of the game (see Turning embedding on or off).
Turning embedding on or off
Embedding is on by default for every game. As the creator you can turn it off:
In the dashboard: open the game, edit its details, and untick Allow embedding on other sites.
Through the API:
POST /v1/games/:idwith{ "embeddable": false }(see Games & uploads API).
When embedding is off:
https://coolgptgames.com/embed/<slug>shows "Embedding is disabled for this game." with a link to play on Cool GPT Games.The game build itself refuses to load inside any page other than Cool GPT Games.
The Embed option disappears from the game's share menu.
A game that isn't currently playable (for example unpublished or delisted) shows "This game isn't playable right now." in the embed.
What works in an embed
Embedded games play as guests. Browsers keep a third-party iframe's storage separate from the same site opened directly, so the embed can't see a player's Cool GPT Games sign-in, and the embed has no sign-in button.
Feature | In an embed |
|---|---|
Gameplay, input, audio, fullscreen, gamepad | Works, as long as you pass the |
The score bridge (below) | Works |
Remote config ( | Works |
Local saves ( | Works as guest saves in the browser's storage for your site. They aren't synced to an account. |
Multiplayer rooms | Works as for any guest |
Sign-in | Not available. Players see the game's guest prompts. |
XP, levels, achievements | Not recorded (guest). The game gets its normal guest responses. |
Cloud saves | Not available (guest) |
Reading the game's global leaderboard ( | Works (friends leaderboards are empty for guests) |
Score submission | Scores aren't recorded on Cool GPT Games (guest). They are still forwarded to your page through the bridge. |
Tournaments | Listing tournaments and standings works; joining and competing need a signed-in player |
Ranked play, in-game purchases | Not available (they need a signed-in player) |
Ads | Only non-personalised (contextual) ads. Cool GPT Games' consent banner doesn't appear inside embeds, so no personalised ads are ever served there. |
Games need no changes to work in an embed. A game written with the GameSDK already handles guests. See How games run, Saves & cloud progress and Ads & rewards for how guest mode behaves.
The score bridge
When a game running in an embed reports lifecycle events or scores through the GameSDK, the embed forwards a copy of each event to your page (the parent window) with window.postMessage. Your page listens for message events.
Message format
Every bridge message is a plain object:
{
source: "coolgptgames"; // always this value
v: 1; // bridge protocol version
type: "ready" | "gamestart" | "score" | "gameover";
game: string; // the game's slug
score?: number; // on "score", and on "gameover" when the game passed one
}Message types
| Sent when the game calls |
| Repeats? |
|---|---|---|---|
|
| No | Yes: sent, then re-sent after about 0.3 s and about 1 s |
|
| No | Yes: sent, then re-sent after about 0.3 s and about 1 s |
|
| Yes | No: sent exactly once per call |
|
| Only if the game passed a number | No: sent exactly once per call |
Notes:
readyandgamestartare repeated so a page whose listener attaches a moment late still hears them. Treat them as idempotent state signals: "the game is ready" or "a run is in progress", not events to count.scoreandgameoveraren't repeated, so you can count them.A game may call
ready()orstart()more than once (for examplestart()at the beginning of every round), and you get a message each time.A game that submits scores through the replay-verification path (see Scores, leaderboards & anti-cheat) produces a
scoremessage for eachGameSDK.replay.submit(score)call, just likesubmitScore. The value is the score the game reported, before any server-side verification.Games that don't use the GameSDK produce no bridge messages.
Only these four types and fields cross the bridge. The player's identity, sign-in token and handle are never sent to your page.
Listening
Attach your listener before the iframe loads, so you don't miss the first ready. Check both the origin and the source:
<script>
// Registered before the iframe below is parsed, so the first "ready" can't be missed.
let best = 0;
window.addEventListener("message", (event) => {
// 1. Only accept messages from Cool GPT Games…
if (event.origin !== "https://coolgptgames.com") return;
// 2. …and only from this particular iframe (matters if you embed several games).
const frame = document.getElementById("cgg-game");
if (!frame || event.source !== frame.contentWindow) return;
const msg = event.data;
if (!msg || msg.source !== "coolgptgames" || msg.v !== 1) return;
switch (msg.type) {
case "ready":
document.body.classList.add("game-ready");
break;
case "gamestart":
document.body.classList.add("game-running");
break;
case "score":
if (typeof msg.score === "number" && msg.score > best) {
best = msg.score;
document.getElementById("best").textContent = String(best);
}
break;
case "gameover":
document.body.classList.remove("game-running");
showPlayAgain(typeof msg.score === "number" ? msg.score : null); // your own function
break;
}
});
</script>
<p>Best score: <span id="best">0</span></p>
<iframe id="cgg-game"
src="https://coolgptgames.com/embed/space-miner-3fa2c1"
width="800" height="600" style="border:0;max-width:100%"
allow="fullscreen; autoplay; gamepad" allowfullscreen></iframe>For a script-inserted iframe, add the listener first and only then set the iframe's src or append it to the page.
Several games on one page
Each message carries the game's slug in game, and event.source tells you which iframe sent it. Compare event.source against each iframe's contentWindow to route messages to the right widget.
Security
Always check
event.origin === "https://coolgptgames.com". Any window canpostMessageyour page. Without the check, another frame or a popup could send fakescoreevents.Also check
event.sourceagainst your iframe'scontentWindow, anddata.source === "coolgptgames".Bridge scores are unverified. They are what the game reported in the player's browser, which the player controls. They haven't been through Cool GPT Games' anti-cheat, and for guests they aren't recorded server-side at all. Use them for fun on-page features (a "best score" badge, a local high-score table, a "play again" prompt). Don't award prizes, money, credits or anything of value based on bridge messages alone. - Messages are one-way. The bridge sends from the embed to your page only. Nothing your page posts into the iframe is read, and your page can't control the game or reach the player's account. - The game is sandboxed. The game runs in a locked-down frame inside the embed, on a separate origin, and can't script your page. You don't need to add a
sandboxattribute to your own<iframe>. If you do, include at leastallow-scripts allow-same-origin allow-popups, or the embed won't work.Target origin. The embed posts with target origin
"*"because it can't know your page's origin in advance. That's why only non-sensitive data is ever sent.
Troubleshooting
Symptom | Likely cause |
|---|---|
"Embedding is disabled for this game." | The creator turned embedding off |
"This game isn't playable right now." | The game isn't published, or has been delisted |
Frame loads but the game area stays blank | Your page is served over |
No fullscreen, no sound until click, no gamepad | Missing |
No bridge messages at all | Listener attached after the iframe loaded (you missed |
| The game calls neither |
See also
How games run: the player, the sandbox and guest mode - GameSDK core reference:
ready,start,submitScore,gameOverGameSDK saves & scores reference:
replay.submitScores, leaderboards & anti-cheat: server-verified scores - Games & uploads API: the
embeddablesetting