> For the complete documentation index, see [llms.txt](https://wiki.playgama.com/playgama/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.playgama.com/playgama/guides/deploy-a-game-on-your-own-domain.md).

# Deploy a game on your own domain

## Overview

This article explains how to run a Playgama Bridge game on a page you control — any domain of yours: a landing page, your portal, or a marketing page. The game runs **unchanged** inside an iframe, while a small "wrap host" page proxies the Bridge SDK over `postMessage` and serves Playgama ads. This mode is called **standalone**.

## Prerequisites

1. **The game integrates the Bridge SDK.** It already talks to Playgama Bridge (ads, storage, player, etc.) — nothing about the game build has to change for standalone.
2. **The game is deployed at a public URL.** Its `index.html` must launch the game when opened directly in the browser.
3. **You have a `clid`** from your Playgama partner cabinet. It activates ads and attributes analytics/revenue to your channel.

## Limitations

{% hint style="info" %}
This guide does **not** cover cloud saves, authentication, or payments. The wrap host *does* support wiring your own backend for these — see the optional `auth`, `cloudSave`, and `payments` blocks in [Connect your backend](#connect-your-backend).
{% endhint %}

## How it works

```
                                 loads
 ┌──────────────────────────┐   wrap.v1.js   ┌──────────────────────────┐
 │  Game in iframe          │ ◄────────────► │  This page (host)        │
 │  ?platform_id=standalone │   postMessage  │  wrap-host.v1.js         │
 │  Bridge → PLAYGAMA_WRAP  │                │  PLAYGAMA_WRAP_HOST      │
 └──────────────────────────┘                └──────────────────────────┘
```

The game loads in an iframe with `?platform_id=standalone`. That switches the in-game Bridge into standalone mode: it loads `wrap.v1.js` and starts talking to your host page over `postMessage`. Your host page loads `wrap-host.v1.js`, which answers those Bridge calls and runs Playgama ads. The game itself is untouched.

## Setup in 3 steps

### 1. Place the game iframe

```html
<iframe
  id="game-iframe"
  src="https://your-cdn.example.com/game/index.html?platform_id=standalone"
  allow="fullscreen; autoplay; gamepad; gyroscope; accelerometer; clipboard-read; clipboard-write; encrypted-media; picture-in-picture; screen-wake-lock; pointer-lock;"
></iframe>
```

`src` points to your deployed game's `index.html`. The URL **must** end with `?platform_id=standalone`.

### 2. Add the SDK scripts

```html
<script src="https://playgama.com/ads/common.v0.2.js"></script>
<script src="https://playgama.com/platform-sdk/wrap-host.v1.js"></script>
```

Order matters — the Ads SDK (`common.v0.2.js`) must load **before** `wrap-host.v1.js`.

{% hint style="warning" %}
If you swap the order, wrap-host throws: `Playgama Wrap host requires Playgama Ads SDK to be loaded before wrap-host.v1.js`.
{% endhint %}

### 3. Initialize the wrap host

```html
<script>
  window.PLAYGAMA_WRAP_HOST = window.PlaygamaWrapHost.init({
    gameFrame: '#game-iframe',                          // the game iframe above
    clid: '<your-clid>',                                // from your Playgama partner cabinet
    gameId: '<your-game-id>',                           // internal game id — splits stats per game
    allowedGameOrigin: 'https://your-cdn.example.com',  // must match the iframe origin
  })
</script>
```

The result is assigned to `window.PLAYGAMA_WRAP_HOST` — the same global the in-game Bridge expects, and the handle you use later to listen to ad events.

## Minimal working example

A complete, copy-pasteable host page with a full-screen game:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>My Standalone Game</title>
  <style>
    html, body { margin: 0; height: 100%; }
    body {
      display: flex;
      flex-direction: column;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    }
    #game-iframe { flex: 1 1 auto; width: 100%; border: 0; display: block; }
  </style>
</head>
<body>

  <iframe
    id="game-iframe"
    src="https://your-cdn.example.com/game/index.html?platform_id=standalone"
    allow="autoplay; fullscreen; gamepad; gyroscope; accelerometer; clipboard-read; clipboard-write; encrypted-media; picture-in-picture; screen-wake-lock; pointer-lock"
  ></iframe>

  <!-- Playgama SDK: Ads first, then wrap-host (order matters). -->
  <script src="https://playgama.com/ads/common.v0.2.js"></script>
  <script src="https://playgama.com/platform-sdk/wrap-host.v1.js"></script>
  <script>
    window.PLAYGAMA_WRAP_HOST = window.PlaygamaWrapHost.init({
      gameFrame: '#game-iframe',
      clid: '<your-clid>',
      gameId: '<your-game-id>',
      allowedGameOrigin: 'https://your-cdn.example.com',
    })
  </script>

</body>
</html>
```

## `init(config)` reference

**`window.PlaygamaWrapHost.init(config): WrapHost`**

Initializes the wrap host: binds it to the game iframe, wires up the Bridge proxy and Playgama ads, and returns the host instance (also assign it to `window.PLAYGAMA_WRAP_HOST`).

### Parameters

`config` is an object with the following fields:

| Parameter           | Type                      | Required | Default | Description                                                                                                                                                        |
| ------------------- | ------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `gameFrame`         | `string` \| `HTMLElement` | Yes      | —       | CSS selector or element of the game iframe, e.g. `'#game-iframe'`.                                                                                                 |
| `clid`              | `string`                  | Yes      | —       | Your partner channel ID from the Playgama partner cabinet. Drives analytics and revenue attribution; must match the `clid` used for the game.                      |
| `gameId`            | `string`                  | Yes      | —       | Internal game ID. Splits analytics/revenue per game when one partner has several games. If you only have one game, its name works fine.                            |
| `allowedGameOrigin` | `string`                  | No       | `'*'`   | Origin (scheme + domain) of the game. wrap-host accepts `postMessage` only from this origin. Recommended in production; must match the origin of the iframe `src`. |
| `disableAds`        | `boolean`                 | No       | `false` | Set to `true` to fully disable ads inside the game.                                                                                                                |
| `auth`              | `object`                  | No       | —       | Custom authentication. See [Authentication](#authentication).                                                                                                      |
| `cloudSave`         | `object`                  | No       | —       | Cloud saves. See [Cloud saves](#cloud-saves).                                                                                                                      |
| `payments`          | `object`                  | No       | —       | In-game payments. See [Payments](#payments).                                                                                                                       |

## Connect your backend

Authentication, cloud saves, and payments are enabled by the **presence** of the corresponding block in `config`. Omit a block and Bridge reports that feature as unsupported to the game: the player is a guest, progress is kept in the game's `localStorage`, and purchases are rejected.

### Authentication

Pass an `auth` object with three functions:

```javascript
auth: {
    // Return the current user (or a guest).
    // Shape: { id, name, photos: [], isAuthorized: boolean, ...extra }
    getUser: () => Promise.resolve({
        id: 'guest-xxxx', name: 'Guest', photos: [], isAuthorized: false,
    }),
    // Called on Bridge.player.authorizePlayer(). Show your login modal,
    // resolve with the profile on success.
    authorizeUser: () => showYourLoginModal(),
    // Log the user out.
    logout: () => clearYourSession(),
}
```

### Cloud saves

Pass a `cloudSave` object with two functions:

```javascript
cloudSave: {
    // Read the saved state (an arbitrary object).
    getState: () => yourBackend.loadSave(currentUserId),
    // Write the state. Return true/false.
    setState: (state) => yourBackend.writeSave(currentUserId, state),
}
```

### Payments

Pass a `payments` object with the purchase flow functions:

```javascript
payments: {
    purchase:        (product) => yourPaymentFlow(product),
    getPurchases:    () => yourBackend.listPurchases(),
    consumePurchase: ({ orderId, externalId }) => yourBackend.consume(orderId),
    confirmDelivery: ({ orderId, externalId }) => yourBackend.confirm(orderId),
}
```

## Troubleshooting

* **`Playgama Wrap host requires Playgama Ads SDK to be loaded before wrap-host.v1.js`** — the scripts are in the wrong order. Load `common.v0.2.js` before `wrap-host.v1.js`.
* **The game never connects to the host** — check that the iframe `src` ends with `?platform_id=standalone`, and that `allowedGameOrigin` matches the iframe's origin (or is left at the default `'*'`).

***

## Agent Instructions: Querying This Documentation

If you need additional information that is not directly available on this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.playgama.com/playgama/guides/deploy-a-game-on-your-own-domain.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language. The response will contain a direct answer with relevant excerpts and sources from the documentation.
