Embedded hosted checkout lets your page keep its layout while COPE renders the payment form inside an iFrame. Your site owns the surrounding experience. COPE owns the checkout route, payment collection, tax finality, order creation, and buyer-facing terminal states.
Use embedded checkout when you need a custom storefront or in-page checkout modal. Use redirect checkout when the simplest integration is enough or when a browser blocks the iFrame flow.
📄 Full documentation: [Embedded hosted checkout - COPE]
Requirements
Before creating embedded checkout sessions:
Create a publishable key for the COPE business
Register every parent page origin that may host the iFrame (e.g.
https://shop.example.com)Use an origin only: scheme, host, and optional port – no path, query string, or fragment
HTTPS only in production (
http://localhostfor development only)Configure allowed success and cancel URLs for redirect-based completion or fallback
The parent origin must exactly match the browser page origin that calls checkout({ embed_origin }). https://shop.example.com and https://www.shop.example.com are different origins.
Integration
ts
import { CopeCart } from "@copecart/sdk" const cope = new CopeCart({ publishableKey: "cope_pk_live_...", }) async function openEmbeddedCheckout(productId: string, planId: number) { const cart = await cope.createCart({ currency: "EUR" }) await cope.addLine(cart.id, { product_id: productId, plan_id: planId, }) await cope.setBuyerIdentity(cart.id, { email: "buyer@example.com", tax_location: { country: "DE", postal_code: "10115" }, }) await cope.reprice(cart.id) const checkout = await cope.checkout(cart.id, { embed_origin: window.location.origin, success_url: "https://shop.example.com/thank-you", cancel_url: "https://shop.example.com/cart", consents: [{ type: "buyer_tos" }], }) return cope.mountCheckout("#cope-checkout-frame", checkout, { fallback: "redirect", onReady: () => showCheckoutFrame(), onResize: ({ height }) => resizeContainer(height), onSuccess: () => showOrderConfirmation(), onCancel: () => closeCheckoutFrame(), onError: ({ code, retryable }) => reportCheckoutError(code, retryable), }) }The checkout response includes both URL shapes:
Field | Meaning |
| Redirect route, e.g. |
| iFrame route, e.g. |
| Approved parent origin returned by COPE |
mountCheckout() refuses to mount when checkout.embedOrigin is missing or does not exactly match window.location.origin.
Mount behavior
mountCheckout() creates the iFrame for you:
src→checkout.embedCheckoutUrltitle→COPE checkoutallow→payment *for browser wallet supportreferrerPolicy→no-referrerwidth→100%min-height→720pxNo
sandboxattribute
Do not build the iFrame manually – the SDK also performs the trusted mount handshake and filters all iFrame messages by origin, source window, message source, and version.
Fallback
Set fallback: "redirect" for buyer-safe recovery if the iFrame does not complete the trusted ready handshake before readyTimeoutMs:
ts
cope.mountCheckout("#cope-checkout-frame", checkout, { fallback: "redirect", readyTimeoutMs: 8000, onFallbackRedirect: () => { console.log("Falling back to hosted checkout") }, })With the default fallback: "error", the SDK calls:
ts
onError({ code: "load_failed", retryable: true })Events
The iFrame sends sanitized events to the SDK. Callback payloads do not include checkout credentials, payment client secrets, or buyer PII.
Event | Meaning |
| iFrame loaded and ready |
| Payment completed successfully |
| User cancelled |
| Error in payment process (incl. |
| iFrame height changed |
For the raw sanitized event stream:
ts
cope.mountCheckout("#cope-checkout-frame", checkout, { onMessage: (event) => { analytics.track("cope_checkout_embed_event", event) }, })Security model
Embedded checkout has two layers of authorization:
COPE validates
embed_originagainst the business allowlist when the checkout session is createdThe iFrame route validates the same embed contract before rendering the payment form
The SDK sends the mount message with a specific targetOrigin – never *. iFrame messages are only accepted when event.origin, event.source, event.data.source (cope.checkout), and event.data.version (1) all match.
Use cases
In-page checkout modal
The payment form opens as an overlay within your page. No redirect, no loss of context – the user stays within your navigation and layout throughout the entire checkout.
SaaS upgrade flow
A user upgrades from free to pro directly in the dashboard. mountCheckout() renders the payment form as an iFrame in a modal or dedicated section of the page, without losing the current state.
Custom storefront
You build a fully custom product page with your own branding – COPE only renders the payment form inside the iFrame. Your page retains full control over layout, colors, and user experience.
High-conversion checkout
Every redirect is a potential drop-off point. Embedded checkout eliminates that friction and keeps the user on your page all the way to successful payment.
Troubleshooting
Error | Likely cause | Fix |
| Origin not registered | Register the exact parent origin, create a new session |
|
| Pass |
| Session created for a different origin | Call |
iFrame never becomes ready | Token expired, blocked, or handshake failed | Use |
Browser wallet unavailable | Wallet domain registration incomplete | Verify |

