Skip to content

Preview. The API is shared with design partners and may change before launch. Register interest for sandbox access.

Iframe embed

The iframe embed shows the same offer as the drop-in SDK, but inside an isolated iframe served from Phew. No Phew JavaScript runs in your page, nothing from your page is readable by Phew, and the only connection between the two is a small set of postMessage events. This is the integration most banks and payment providers choose for their payment pages, hosted checkouts and in-app web views.

Your server ──▶ POST /v1/offers ──▶ offer.embed_url
Your page ──▶ <iframe src=embed_url> ──▶ customer chooses a plan
◀── postMessage: phew:change
Your server ──▶ POST /v1/policies when the order is paid
  1. Create the offer on your server with POST /v1/offers. The response includes embed_url: a signed, single-use URL for that offer that expires with it.

    {
    "id": "off_01JD7Q8S4M5W2X3Y4Z6A7B8C9D",
    "object": "offer",
    "embed_url": "https://embed.getphew.com/o/off_01JD7Q8S4M5W2X3Y4Z6A7B8C9D?t=eyJ2Ijox...",
    "items": [{ "reference": "SKU-CBX-48", "eligible": true, "plans": ["..."] }]
    }

    If no item is eligible, there’s nothing to show: skip the iframe.

  2. Render the iframe where the offer should appear.

    <iframe
    id="phew-offer"
    src="https://embed.getphew.com/o/off_01JD7Q8S...?t=eyJ2Ijox..."
    title="Product protection from Phew"
    sandbox="allow-scripts allow-same-origin allow-popups"
    style="width: 100%; border: 0"
    ></iframe>
  3. Listen for messages, always checking the origin:

    const frame = document.getElementById("phew-offer");
    window.addEventListener("message", (event) => {
    if (event.origin !== "https://embed.getphew.com" || event.source !== frame.contentWindow) return;
    const message = event.data;
    if (message.type === "phew:resize") frame.style.height = `${message.height}px`;
    if (message.type === "phew:change") {
    // message.selections: [{ reference, plan }], message.total: premium in minor units
    }
    });
  4. Create the policy on your server when the order is paid, with the offer ID and the selections, using POST /v1/policies.

type Fields When
phew:ready offer The offer has rendered
phew:resize height The content height changed; set the iframe height to match
phew:change offer, selections, total The customer chose a plan, changed plan or declined
phew:error code The offer couldn’t load; hide the iframe and continue

Messages are sent only to the parent window, and the iframe ignores all incoming messages except phew:update, which you can send with a new embed_url after the cart changes.

Pass appearance when you create the offer, and the embed renders in your colours and type:

{
"currency": "NOK",
"market": "NO",
"items": ["..."],
"embed": {
"appearance": { "theme": "light", "color_primary": "#0b5fff", "border_radius": 10, "font": "inter" }
}
}

Load embed_url in a web view (WKWebView on iOS, WebView on Android). Messages are delivered through the platform’s script bridge: register a handler named phew and you’ll receive the same message objects as on the web.

  • Isolation. The offer runs in its own origin. It can’t read your DOM, cookies, storage or form fields, and you don’t load any Phew script.
  • Strict CSP. You only need frame-src https://embed.getphew.com.
  • Server-controlled. The embed can only show an offer your server created, with your credentials, for that cart.
  • Signed and short-lived. embed_url is signed, bound to one offer, and expires with it.