Checkout
Embedded (slide-out iframe) vs hosted-redirect checkout, return detection, and the shopping beacon.
Bolder’s checkout can be integrated in two modes. Choose based on the UX you want and the payment methods your shop uses.
| Mode | UX | Gateway redirects | Setup |
|---|---|---|---|
| Embedded | Customer stays on your page; checkout opens in a slide-out iframe | Handled transparently — SDK navigates the top-level window when a gateway (PayPal, Webpay, Khipu) redirects | Import bolder-checkout or include checkout.umd.cjs |
| Hosted redirect | Customer navigates to Bolder’s checkout page, then returns to your page | Native — no iframes involved | Pass return_url in the checkout link |
Both modes share the same return-detection API so your page always knows when a customer comes back after payment.
Embedded mode
The checkout opens in a closeable slide-out panel on top of your page. When an inline payment succeeds the SDK fires a success event directly. When a gateway redirect is required (PayPal, Webpay, Khipu), the SDK breaks out of the iframe and navigates the top-level window — on return, handleReturn() detects the result.
Install:
npm install bolder-checkout
# or use the script tag: https://assets.bolder.run/checkout.umd.cjs
Usage with bolder-storefront cart:
import { createStorefront, openCheckout } from 'bolder-storefront'
// or: import { openCheckout } from 'bolder-checkout'
createStorefront({ shop: 'acme' }).then(function(storefront) {
// Cart's checkout() returns a URL — open it in the embedded slider.
document.querySelector('#checkout-btn').addEventListener('click', function() {
storefront.cart.checkout(function(err, url) {
if (err) return
openCheckout({ checkoutUrl: url })
})
})
})
The ShoppingBeacon component wires this automatically — you don’t need to
handle it manually if you’re using the beacon.
Usage with your own order API (no storefront cart):
import { openCheckout } from 'bolder-checkout'
// Your backend creates the order and returns a checkout_url.
const { checkout_url } = await fetch('/api/orders', { method: 'POST' }).then(r => r.json())
const session = openCheckout({ checkoutUrl: checkout_url })
session.on('success', () => showConfirmation())
session.on('closed', () => console.log('checkout closed'))
Hosted redirect mode
The customer navigates to Bolder’s checkout UI (same as for a regular hosted shop). When they complete (or cancel) their order, Bolder redirects them back to the URL you specified as return_url.
This is the simpler mode — no iframes, no postMessage, no SDK required on the checkout page itself.
Navigating to the checkout:
Use redirectToCheckout() — it accepts the same URL options as openCheckout() and appends return_url automatically:
import { redirectToCheckout } from 'bolder-checkout'
// or: import { redirectToCheckout } from 'bolder-storefront'
redirectToCheckout({ checkoutUrl: cartData.checkout_url })
// Optional: override the return page (defaults to the current page)
redirectToCheckout({ checkoutUrl: cartData.checkout_url, returnUrl: 'https://mysite.com/thanks' })
Script-tag: Bolder.checkout.redirect({ checkoutUrl: cartData.checkout_url })
Bolder stores return_url on the checkout session when the checkout page first loads and uses it to redirect back after any gateway round-trip. The return_url must be a URL whose hostname matches the shop’s configured domain or an allowed embed origin — Bolder rejects unknown hosts to prevent open redirects.
What the customer receives on return:
Bolder appends two parameters before redirecting back:
https://your-site.com/products/hat?checkout_session=ABC123&checkout_status=success
| Parameter | Values |
|---|---|
checkout_session |
The order permalink — identifies which order was placed |
checkout_status |
success or cancelled |
Return detection
Whether you use embedded or hosted redirect mode, load bolder-checkout on the
page the customer returns to. It runs handleReturn() automatically at module
load — before any framework router can consume the URL — cleans the params, and
fires a bolder:checkout:return event.
Listening for the event (registers before module load completes):
import { handleReturn } from 'bolder-checkout'
// handleReturn() already ran by the time the next line executes.
// Use document.addEventListener *before* the import for early listeners,
// or use getLastReturn() for components that mount later.
document.addEventListener('bolder:checkout:return', function(e) {
const { sessionCode, status } = e.detail // status: 'success' | 'cancelled'
if (status === 'success') showConfirmationBanner(sessionCode)
})
Checking in a late-mounting component (misses the event):
import { getLastReturn } from 'bolder-checkout'
// or: import { getLastCheckoutReturn } from 'bolder-storefront'
// Call this inside your component's mount/init callback:
const ret = getLastReturn()
if (ret?.status === 'success') showConfirmationBanner(ret.sessionCode)
if (ret?.status === 'cancelled') showRetryPrompt()
handleReturn() return value — { sessionCode, status } if checkout params
were present, undefined otherwise. Also available via Bolder.checkout.handleReturn() in script-tag usage.
URL cleanup — handleReturn() removes checkout_session and checkout_status
from the URL via history.replaceState so a page refresh doesn’t re-trigger the
handler.
Shopping beacon integration
The ShoppingBeacon component integrates both modes automatically:
-
Embedded mode: the “Proceed to checkout” button in the cart slide-out calls
Bolder.checkout.open({ checkoutUrl }). The beacon passesreturn_url(the current page URL) andoriginto the checkout iframe automatically. -
Return detection: on every page load, if
getLastReturn()reportsstatus === 'success', the beacon displays a success toast notification. In hosted themes the toast uses the styledToastsmodule; in headless mode a self-contained fallback renders instead.
No additional wiring is needed — mount the beacon and both flows work out of the box.
import { createStorefront, ShoppingBeacon } from 'bolder-storefront'
createStorefront({ shop: 'acme' }).then(function(storefront) {
storefront.mount(ShoppingBeacon, '#beacon-container')
})
To handle the return yourself and suppress the beacon’s built-in toast, listen to
the event before the beacon mounts and call e.stopImmediatePropagation(), or
simply don’t use the beacon and wire your own UI around getLastReturn().
Agentic checkout (UCP)
Every storefront also exposes an agent-facing checkout API — the Universal Commerce
Protocol — discoverable at /.well-known/ucp, for shopping agents
that complete a purchase without a human driving the browser.