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 embed | URL 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 Gateway | The 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.
<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.
| Event | Payload | What to do |
|---|---|---|
height | Content height in pixels | Resize the iFrame so the form never scrolls internally |
top | Vertical offset | Scroll the parent page, e.g. when the checkout step changes |
transaction | Transaction object including status | Update your UI — never fulfil an order from this alone |
closeModal | Redirect URL | Navigate the parent page yourself; the iFrame may not redirect your site |
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.