Iframe Embed

The iframe integration lets you embed depositOS in any web application, regardless of framework. The widget runs in a separate hosted page and communicates with your parent page via the postMessage API.

This approach is ideal for non-React applications, environments where you cannot install npm packages, or when you need strong isolation between the widget and your app.

Integrator note: you do not need to provide API keys in frontend integration. The iframe host and backend handle provider credentials server-side.

Overview

The iframe integration has two parts:

  1. The iframe host — A standalone app that renders the depositOS widget. You host this on your own domain or subdomain (e.g., https://embed.deposit-os.com).
  2. Your parent page — Loads the iframe and communicates with it via postMessage to send configuration and receive events.

Hosting the Iframe App

The apps/iframe-host directory contains a ready-to-deploy Vite application. Build and host it on any static hosting provider:

cd apps/iframe-host
pnpm install
pnpm build

The build output in dist/ is a static site you can deploy to Vercel, Netlify, Cloudflare Pages, or any web server.

Iframe Host Environment Variables

Set these values on your iframe-host deployment:

| Variable | Required | Notes | |---|---|---| | VITE_API_BASE_URL | Recommended | depositOS API base URL used by the widget | | VITE_DYNAMIC_ENVIRONMENT_ID | If wallet mode used | Dynamic environment ID for wallet connection | | VITE_IFRAME_RENDER_TYPE | No | Default render type: inline, popup, or button | | VITE_IFRAME_BUTTON_TEXT | No | Default launcher button text in button mode |

Parent Page Setup

On your page, create an iframe pointing to the hosted widget URL. You can pass initial configuration via URL parameters or via postMessage after the iframe loads.

Basic HTML Example

<div id="depositos-container" style="width: 420px; height: 600px;">
  <iframe
    id="depositos-iframe"
    src="https://embed.deposit-os.com"
    style="width: 100%; height: 100%; border: none;"
    allow="clipboard-write"
  ></iframe>
</div>

<script>
  const iframe = document.getElementById("depositos-iframe");

  const config = {
    destChain: 42161,
    destToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
    destAddress: "0xYourTreasuryAddress",
    enableWallet: true,
    enableLayerswap: true,
    enablePrivateMode: true,
    theme: "dark",
  };

  // Wait for the iframe to signal it's ready, then send config
  window.addEventListener("message", function (event) {
    const data = event.data;
    if (!data || typeof data.type !== "string") return;

    switch (data.type) {
      case "depositos:ready":
        // Iframe is loaded — send the configuration
        iframe.contentWindow.postMessage(
          { type: "depositos:config", config: config },
          "*"
        );
        break;

      case "depositos:success":
        console.log("Deposit successful!", data.txHash);
        // Handle success — redirect, show confirmation, etc.
        break;

      case "depositos:close":
        console.log("Widget closed by user");
        // Hide the iframe or navigate away
        break;

      case "depositos:resize":
        // Optionally auto-resize the iframe container
        document.getElementById("depositos-container").style.height =
          data.height + "px";
        break;

      case "depositos:error":
        console.error("Widget error:", data.error);
        break;
    }
  });
</script>

Passing Config via URL Parameters

As an alternative to postMessage, you can pass configuration directly in the iframe URL. This is useful for static pages or server-rendered HTML where you know the config at page load time.

Individual Parameters

<iframe
  src="https://embed.deposit-os.com?destChain=42161&destToken=0xaf88d065e77c8cC2239327C5EDb3A432268e5831&destAddress=0xYourAddress&theme=dark"
  style="width: 420px; height: 600px; border: none;"
></iframe>

Base64-encoded Config

For complex configurations, encode the full config object as base64 JSON:

<iframe
  src="https://embed.deposit-os.com?config=eyJkZXN0Q2hhaW4iOjQyMTYxLC4uLn0="
  style="width: 420px; height: 600px; border: none;"
></iframe>

Individual URL parameters take precedence over values in the base64 blob, so you can use the blob as a base and override specific fields.

Render Modes

The iframe host supports three display modes:

  • inline — renders the widget directly in the iframe (default)
  • popup — auto-opens a modal when the iframe loads
  • button — shows a launcher button; clicking opens the modal

Use type (or renderType) in the iframe URL:

<iframe src="https://embed.deposit-os.com?type=inline&config=..." ...></iframe>
<iframe src="https://embed.deposit-os.com?type=popup&config=..." ...></iframe>
<iframe src="https://embed.deposit-os.com?type=button&buttonText=Deposit%20Now&config=..." ...></iframe>

Message Protocol

Communication between the parent page and the iframe follows a typed message protocol.

Parent to Iframe (Inbound)

| Message Type | Payload | Description | |---|---|---| | depositos:config | { config: Partial<DepositOSConfig> } | Send or update the widget configuration. Can be sent at any time to update config dynamically. | | depositos:displayType | { displayType: "inline" \| "popup" \| "button", buttonText?: string } | Update render type and optionally set launcher button text dynamically. |

Iframe to Parent (Outbound)

| Message Type | Payload | Description | |---|---|---| | depositos:ready | — | The iframe has loaded and is ready to receive configuration. | | depositos:success | { txHash?: string } | A deposit completed successfully. | | depositos:close | — | The user clicked the close button. | | depositos:resize | { height: number } | The widget content height changed. Use this to auto-size the iframe. | | depositos:error | { error: string } | A configuration or runtime error occurred. |

Updating Config Dynamically

You can send a new depositos:config message at any time to update the widget without reloading the iframe. The new config is shallow-merged with the existing one:

// Update just the order reference
iframe.contentWindow.postMessage(
  {
    type: "depositos:config",
    config: { orderRef: "order-99887" },
  },
  "*"
);

You can also switch render mode dynamically:

iframe.contentWindow.postMessage(
  {
    type: "depositos:displayType",
    displayType: "button",
    buttonText: "Open Deposit",
  },
  "*"
);

Dynamic recipient address per user

If each user in your app has a different recipient wallet, send destAddress dynamically through depositos:config.

Recommended pattern:

  1. Wait for depositos:ready
  2. Send user-specific config including destAddress
  3. Re-send when the active user changes
const iframeOrigin = "https://embed.deposit-os.com";
const iframe = document.getElementById("depositos-iframe");

function sendUserConfig(user) {
  iframe.contentWindow.postMessage(
    {
      type: "depositos:config",
      config: {
        destChain: 42161,
        destToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        destAddress: user.depositAddress, // dynamic recipient
        orderRef: user.id, // optional tracking
      },
    },
    iframeOrigin
  );
}

window.addEventListener("message", (event) => {
  if (event.origin !== iframeOrigin) return;
  if (event.data?.type === "depositos:ready") {
    sendUserConfig(currentUser);
  }
});

// Later, if user changes:
// sendUserConfig(nextUser);

Security Considerations

  • Always specify a target origin instead of "*" when sending messages in production:
iframe.contentWindow.postMessage(
  { type: "depositos:config", config: config },
  "https://embed.deposit-os.com"
);
  • Validate the origin of incoming messages before processing them:
window.addEventListener("message", function (event) {
  if (event.origin !== "https://embed.deposit-os.com") return;
  // Process event.data
});
  • Host the iframe app on the same domain or a trusted subdomain to align with your Content Security Policy.