- Checkout
- API reference
Checkout JavaScript events
The events the Checkout iframe emits to the page around it — load, customer type, address and shipping changes, order total, checkboxes, network errors — with the payload each one carries, plus suspend and resume, and how to forward events to an analytics tool.
The Checkout iframe talks to the page it’s embedded in. It emits an event whenever the
customer does something the surrounding page might care about — enters an address, picks a
shipping option, ticks a checkbox — and it accepts two commands, suspend and resume,
so your page can freeze the iframe while it updates the order behind the scenes. This page
is the catalogue of those events and their payloads. Treat everything here as
presentational: use it to keep your own cart panel in sync or to feed analytics, and use
the Checkout API as the source of truth for anything you act on.
Getting the checkout API handle
Section titled “Getting the checkout API handle”The script inside html_snippet installs a global accessor on your page once the iframe
has rendered. You pass it a function and it hands back the checkout API object.
Render Checkout snippet documents that accessor and
its current name. Every example below assumes you already hold the resulting api object.
Register listeners with api.on(), passing an object whose keys are event names:
api.on({ load: function (data) { // data is the payload documented below }, order_total_change: function (data) { updateMerchantPanelTotal(data.order_total); },});Suspending and resuming around an order update
Section titled “Suspending and resuming around an order update”When your own page changes the cart — the customer edits a quantity, applies a coupon,
removes a line — the iframe doesn’t know about it until you push the change to the
Checkout API. suspend locks the iframe so the customer can’t interact with a stale
total. resume unlocks it and makes it refresh from the updated order.
api.suspend();// POST the update to the order location URI, then:api.resume();A suspend resumes itself automatically after 10 seconds. Disable that if your update can
legitimately take longer, and make sure every code path still calls resume:
api.suspend({ autoResume: { enabled: false } });Between suspend and resume, update the order with a POST to the order location URI
you already hold. Never create a new order to reflect a cart change — that issues a new
order id and orphans the one the customer is looking at.
The event catalogue
Section titled “The event catalogue”| Event | Fires when | Payload |
|---|---|---|
load | The checkout iframe has rendered | Customer type and the address fields known so far |
user_interacted | The customer first touches the iframe | type — mousedown or keydown, or click when the first touch is an express checkout button |
customer | The checkout detects or changes customer type | type — person or organization |
change | Billing details change — postal code, country, email | The changed fields. In AT and DE, narrowed to country, postal_code and city |
billing_address_change | A valid billing address is detected | postal_code, country |
shipping_address_change | A valid shipping address is detected | postal_code, country |
shipping_option_change | The customer selects a shipping option | The full option — price and tax_amount in minor units, tax_rate a percentage |
shipping_address_update_error | Updating shipping failed | Empty object |
order_total_change | The order total changes | order_total in minor units |
checkbox_change | A checkbox is ticked or unticked | key, checked |
can_not_complete_order | The customer needs an alternative payment option, for example after a declined credit check | Empty object |
network_error | The iframe detects a network problem | Empty object |
redirect_initiated | The customer is about to be redirected to your confirmation page | true |
load_confirmation | The confirmation snippet has rendered | Empty object |
validation_callback | The customer clicked Pay order, before the server request | Empty object, plus a callback |
Payload shapes
Section titled “Payload shapes”load reports what the checkout already knows, so it’s the event to seed your panel
from. shipping_address.country is an alpha-3 code.
{ "customer": { "type": "person" }, "shipping_address": { "country": "swe", "postal_code": "16972" }}change carries whichever billing fields the customer has supplied. Values may be
prefilled or obfuscated, and the object is often partial.
{ "email": "shopper@example.com", "postal_code": "12345", "country": "deu"}shipping_option_change carries the whole option. price and tax_amount are in minor
units; tax_rate is a percentage with two implicit decimals, so 2500 is 25%.
{ "id": "express", "name": "Express delivery", "description": "Delivered the next working day", "promo": "Free over 500 SEK", "price": 9900, "tax_amount": 1980, "tax_rate": 2500}checkbox_change identifies the checkbox by the id you gave it in
options.additional_checkboxes. The older single-checkbox option has no id of its own, so
it reports the fixed key additional_checkbox_from_merchant:
{ "key": "additional_checkbox_from_merchant", "checked": true}Running client-side validation before the purchase
Section titled “Running client-side validation before the purchase”validation_callback fires when the customer clicks Pay order, before Kustom makes
any server request. It’s the only event with a second argument, and you have 10 seconds to
call that callback with a should_proceed value.
Answering late is the same as allowing it. If the 10 seconds pass with no answer, Kustom proceeds with the purchase rather than blocking it. A handler that waits on a slow service, or throws before reaching the callback, doesn’t stop anything — it just delays the customer by ten seconds and then lets the purchase through. Keep the handler fast and synchronous where you can, and never rely on it failing closed.
api.on({ validation_callback: function (data, callback) { callback({ should_proceed: false, message: 'Sorry, we cannot ship to that address.', }); },});data is always an empty object here — it exists only to keep the handler signature
consistent. Enable the event by setting options.require_client_validation to true when
you create the order.
This is a customer-experience check, not a control. It runs in the browser and can be bypassed. Anything that must hold — stock, price, delivery restrictions — belongs in the order validation callback on your server.
Forwarding events to an analytics tool
Section titled “Forwarding events to an analytics tool”The event stream maps cleanly onto a purchase funnel, so it’s worth piping into whatever analytics tool you already run. Register one subscriber and forward everything through it rather than writing a handler per event:
const forward = (eventName, data) => gtag('event', `checkout_${eventName}`, { ...data });
api.on({ load: (data) => forward('load', data), user_interacted: (data) => forward('user_interacted', data), billing_address_change: (data) => forward('billing_address_change', data), shipping_address_change: (data) => forward('shipping_address_change', data), redirect_initiated: (data) => forward('redirect_initiated', data),});Those five events make a usable funnel on their own: iframe rendered, customer engaged, billing entered, shipping entered, redirected to confirmation. Drop-off between any two steps is a real signal about the checkout.
Two cautions. Several events also fire on load to report default or prefilled data, so a naive count will overstate the first funnel step — deduplicate per session. And event payloads can contain personal data such as email and postal code, so check what your analytics tool is allowed to store before you spread the payload into it.
Related
Section titled “Related”- Render Checkout snippet — embed the snippet and get hold of the checkout API object.
- Server-side callbacks — the server half, for anything you need to be authoritative.
- Answer the callbacks — block a purchase from your server rather than the browser.
- Troubleshooting Checkout — what breaks the iframe and how to spot it.
This page is also available as Markdown — append .md to its URL — and is indexed in llms.txt.