FlowAlp

iFrame embedding

July 30, 2026

Embed the FlowAlp Pay payment form in your site with an iFrame: URLs, the allow attribute, payment method limits and resize/transaction events.

With iFrame embedding, the FlowAlp Pay payment form appears inside your own website instead of on a separate page. You can embed a payment page configured in the dashboard, the virtual terminal, or the payment link of a Gateway created through the API.

Choose the URL to embed

What you embedURL for the src attribute
Payment page (Pages tool)https://<instance>.pay.flowalp.com/pay?tid=<PAYMENT_TEMPLATE_ID>
Virtual terminal (vPOS)https://<instance>.pay.flowalp.com/vpos
API-created GatewayThe payment link returned by Create a Gateway

<instance> is your instance name; the tid value is the ID of a payment page built with the Pages tool in the dashboard.

Basic iFrame embedtext
<iframe
  id="checkout-frame"
  src="https://<instance>.pay.flowalp.com/pay?tid=<PAYMENT_TEMPLATE_ID>"
  width="530"
  height="700"
  allow="payment *">
</iframe>

A width of 530 and a height of 700 pixels are proven starting values; with the resize events below the height adjusts itself dynamically.

Wallet support: the allow attribute

Keep the allow="payment *" attribute on the frame — Google Pay only works when it is present. Without it the wallet button will not appear inside the embedded form.

Methods that cannot run inside an iFrame

For security reasons some payment methods refuse to run embedded, among them PostFinance Pay, Reka Pay, PayPal and Coinbase. PostFinance is additionally disabled whenever the browser blocks third-party cookies, which is the default on iOS and macOS.

To keep such methods available, append the GET parameter &breakIframe=true to the embedded URL. The affected external payment page then opens in a new browser tab instead of inside the frame.

React to events from the payment page

The embedded page communicates with your site through postMessage. Two steps are involved: after the iFrame has loaded, you send a handshake containing your origin so the page is allowed to answer; afterwards the page posts JSON-encoded messages with the following events.

EventPayloadWhat to do
heightContent height in pixelsResize the iFrame so the form never scrolls internally
topVertical offsetScroll the parent page, e.g. when the checkout step changes
transactionTransaction object including statusUpdate your UI — never fulfil an order from this alone
closeModalRedirect URLNavigate the parent page yourself; the iFrame may not redirect your site
Listen to checkout eventsJavaScript
var frame = document.getElementById('checkout-frame');

// Handshake: tell the embedded page which origin may receive its events
frame.addEventListener('load', function () {
  frame.contentWindow.postMessage(
    JSON.stringify({ origin: window.location.origin }),
    frame.src
  );
});

window.addEventListener('message', function (event) {
  if (typeof event.data !== 'string') return;
  var data = null;
  try { data = JSON.parse(event.data); } catch (ignore) { return; }
  if (!data || typeof data !== 'object') return;

  // Events arrive wrapped under a single vendor namespace key
  Object.keys(data).forEach(function (key) {
    var events = data[key] || {};

    if (events.height) {
      frame.style.height = parseInt(events.height, 10) + 'px';
    }
    if (events.top !== undefined) {
      window.scrollTo({
        top: frame.offsetTop + parseInt(events.top, 10),
        behavior: 'smooth'
      });
    }
    if (events.transaction && typeof events.transaction === 'object') {
      // UI signal only - fulfil orders after webhook or API confirmation
      console.log('Transaction status:', events.transaction.status);
    }
    if (events.closeModal) {
      window.location.href = events.closeModal;
    }
  });
});

Do not add the appview parameter to the embedded URL if you rely on dynamic height — the two are mutually exclusive.

The messages are JSON strings whose events sit under a vendor-specific top-level key. The listener above handles any key; still, log one message in TEST mode and confirm the structure your account delivers before relying on individual fields.

Confirm the payment server-side

Never expose your API secret in the frontend, and never mark an order as paid because the transaction event reported success. Confirm the final state through webhooks with signature verification, or retrieve the transaction through the API.

Prefer an overlay instead of an inline frame? Continue with the modal window guide, and set up webhooks before going live.