Checkout UI Extensions
A checkout extension is a sandboxed iframe rendered at a named slot in the checkout. It loads from your app’s domain, talks back to the host via the App Bridge postMessage protocol, and self-resizes through aAPP_BRIDGE_RESIZE message.
There is no @launchmystore/checkout-ui-extensions-react package and no
custom hook surface. The host renders your iframe URL inside
<iframe sandbox="allow-scripts allow-forms allow-popups allow-same-origin">
and you build whatever UI you want with plain HTML/CSS/JS — or React, if you
ship your own React bundle.
For showing toasts, reading the live cart, applying discount codes, setting
the order note, updating cart attributes, or changing cart lines from inside
your iframe, see App Bridge for Checkout. That page
documents every wired action and its postMessage payload.
Target Slots
The host renders extensions at any of the following targets. The validator in/api/apps/checkout-extensions accepts target strings matching these
prefixes:
checkout-*(legacy slot-style, current canonical names)checkout.*(bare dot-style alias)purchase.checkout.*(namespaced dot-style alias)purchase.thank-you.*andpurchase.order-status.*(post-order)
Targets not in this list won’t render even if the API accepts them —
they’re reserved until the platform wires the matching slot.
Manifest
Declare checkout extensions underextensions.checkoutExtensions[] in your
app’s app.json:
How the Host Renders It
The checkout host mounts a sandboxed iframe per matched extension:onerror fires), the slot
hides that iframe. There is no error message; the frame just disappears.
Note this only catches load errors — an iframe that loads an empty
document still renders as a blank 60px frame, so always ship real markup.
Bootstrap: App Bridge handshake
The host sends nothing to your iframe on load — there is no init message to wait for. Instead, your iframe initiates the handshake: send aBRIDGE_PING action and wait for the response — the host replies
{ ok: true, host: 'checkout' }.
@launchmystore/app-bridge npm package wraps the
same protocol if you’d rather use a typed client.
Wired Actions (Checkout host)
Full list with payload shapes is in App Bridge for Checkout. Quick reference:
Anything else (modal, resource picker, buyer-journey intercept) is not
wired on the checkout host — those actions are listed in the App Bridge SDK
but the response will time out after 10s on
/checkout.
Resizing the Iframe
The iframe starts at 60px. PostAPP_BRIDGE_RESIZE to resize:
Math.ceil(height) for any positive height you send, smaller or
larger, with no clamp on this path.
Unlike admin extension slots, checkout (and post-purchase) resize messages
do not require an
extensionId — the slot matches the message by
iframe identity (event.source). If you do include extensionId (it’s
available on the iframe URL query string), it must match the one the host
assigned or the message is ignored.Reading Settings From app.json
The host does NOT forward settings into the iframe URL automatically.
If your extension needs runtime config, encode it in your own iframe URL
when you install:
Installing an Extension
Extensions are deployed by the install pipeline viaPOST /api/apps/install-extensions. This is a server-to-server
endpoint gated by the platform’s internal API key (no CORS) — it’s invoked
by the backend during the app install flow, not called directly from a
browser with a merchant access token. The only browser-accepted variant is
a fromCatalog: true catalog copy, which also requires the merchant to own
the target store. The payload mirrors the manifest:
extensions/{domainSlug}/{appHandle}/app.json) are also picked up
by /api/apps/checkout-extensions — useful for dev/test apps.
Caching
/api/apps/checkout-extensions returns a 5-minute Cache-Control header
and the checkout client caches the extension list per session.
After publishing a manifest change,
the merchant won’t see it for up to 5 minutes unless they hard-reload.
Security
Iframe sandbox
Iframe sandbox
Extensions render in a sandbox with only
allow-scripts allow-forms allow-popups allow-same-origin. They cannot break out, drive the
parent DOM, or read the parent’s cookies — the only cross-frame
channel is the App Bridge postMessage protocol.Use HTTPS in production
Use HTTPS in production
Serve
iframeUrl over HTTPS so it loads on the HTTPS checkout. The
install pipeline does not enforce the scheme — absolute URLs pass
through untouched (local dev may resolve to http) — so HTTPS is your
responsibility.No access to payment data
No access to payment data
The bridge never exposes card numbers, payment tokens, or PII beyond
what
CART_GET / CUSTOMER_GET / CHECKOUT_TOTALS_GET return.Validate user input server-side
Validate user input server-side
Anything the customer types into your extension is in their browser.
Always validate again on your own backend before persisting.
Testing
- Install on a development store — install your app on a dev store
and reload
/checkoutto render the iframe. - Browser end-to-end — drive
/checkouton your dev store with a headless browser and screenshot the slot. JSON manifests prove the install endpoint works; only a real screenshot proves the iframe rendered and the bridge handshake completed. - Bridge handshake — send
BRIDGE_PINGimmediately on load and log the response. If the response never arrives the parent isn’t the checkout host (e.g. you’re previewing in a standalone tab) and you should render a graceful “preview mode” fallback.
See Also
- App Bridge for Checkout — full action payload reference for the checkout host.
- Post-Purchase Extensions — same iframe model on the order status (thank-you) page; smaller wired-action set.
- Functions — declarative business logic that runs server-side instead of as a UI iframe.