Skip to main content
An embedded checkout is the hosted page in an iframe on your site. The payer never leaves, and what they approve is still rendered on our origin, where your page cannot read or rewrite it. Use @reclack/widget to put it there. This page is about the part that is not JavaScript: which sites are allowed to frame you, and what a browser does about it.
A merchant checkout page with the Reclack checkout embedded in it, sized to fit the page rather than scrolling inside a box.A merchant checkout page with the Reclack checkout embedded in it, sized to fit the page rather than scrolling inside a box.

An embedded checkout: your page around it, ours inside it

Allow your origin

Set the list in the dashboard under Developers, then Embedding. An origin is a scheme and a host, nothing more: https://acme.dev. Paths, query strings and trailing slashes are dropped, only http and https are accepted, and up to twenty origins can be listed.
http://localhost:3000 and https://localhost:3000 are different origins, as are https://acme.dev and https://www.acme.dev. List each one you actually embed from, staging included.

What the browser enforces

Every document we serve answers Content-Security-Policy: frame-ancestors 'none' unless it was opened by the widget. A hand-written <iframe src="https://pay.reclack.com/chk_..."> loads nothing at all, and neither does a framed receipt or billing portal.
That is the first of two checks, and it is the browser’s. The second is the checkout’s own: before it draws anything payable it compares the site framing it against your list, and refuses if it does not match.
The checkout reads the framing origin from the browser, never from a message the embedding page sends. A page that claims to be an allowed origin is still measured against what the browser reports it is. A frame that hides where it came from is refused once a list exists.

What your page is told

The two halves talk over a single MessagePort, handed to the frame and addressed to one origin. Your page learns four things: Nothing else crosses. Your page is not told the amount, the payer’s address or which wallet they used, because it is another origin and the less it knows about what happened in there the less there is to get wrong. Read the payment from the API or the webhook instead. The frame also reports the height it needs, which the widget applies, so your page scrolls as one rather than a box scrolling inside a page.

Sizing, palette and return

  • Height is handled for you. The frame grows and shrinks with its content.
  • Palette follows the merchant’s setting unless your page asks for one. See Appearance.
  • Return is yours to do. Set redirect_url on the session and onSuccess hands it back as redirectUrl for you to navigate to, or ignore it and move the payer along yourself.

When something does not appear

The document refused to be framed. Check that you are launching through the widget rather than writing your own <iframe>, and look in the console for a frame-ancestors refusal.
The checkout loaded and found the framing origin is not on the list. Add the exact origin in Developers, then Embedding, and reload. The message is deliberate: a merchant with a misconfigured list gets an explanation rather than an empty box.
The embedded checkout showing a refusal: this site cannot show this checkout, with a line saying the merchant has not allowed it to be embedded here.The embedded checkout showing a refusal: this site cannot show this checkout, with a line saying the merchant has not allowed it to be embedded here.

A frame from an origin that is not on the list

Check the iframe’s referrer policy. Where a browser cannot name the parent origin itself, the checkout falls back to the referrer, and a frame that suppresses it cannot be identified once a list exists.
Wallets inject per document, and the frame gets its own copy in every browser we have tested. One browser withholds the provider from a frame that does not ask for it, which the widget’s own frame attributes cover, so use launch rather than a frame of your own.

Or do not embed at all

Redirecting to the hosted checkout needs no allowlist, no iframe and no script on your payment page. The trade is that the payer leaves your site. See Hosted checkout.