Frontend events
Look up the callbacks, events, and window messages Bolt sends to your storefront page from Bolt Checkout, the SSO sign-in modal, and the Embedded API.
Each Bolt script reports what the shopper does in its own way. Find the script your page loads:
| Your page loads | Bolt reports through | Section |
|---|---|---|
connect.js, for Bolt Checkout | Callbacks you pass to BoltCheckout.configure, including onNotify events | Bolt Checkout |
account.js, for SSO Commerce | Window messages from the sign-in modal | SSO sign-in modal |
embed.js, for the Embedded API | Events on the Bolt object | Embedded API |
These run in the shopper's browser. Use them to update your page and to send analytics, not as a record of payment: confirm orders on your server with Merchant Callbacks and webhooks.
Bolt Checkout
Pass callbacks in the third argument of BoltCheckout.configure. Every callback is optional. This example sends checkout start and every notification to a Google Tag Manager data layer:
const callbacks = {
onCheckoutStart() {
window.dataLayer?.push({ event: "bolt_checkout_start" });
},
onNotify({ eventName, eventSeverity }) {
window.dataLayer?.push({ event: "bolt_notify", bolt_event: eventName, bolt_severity: eventSeverity });
},
success(transaction, callback) {
// Update your page, then let checkout finish.
callback();
},
};
// token is the order token from your backend, as in Web checkout.
BoltCheckout.configure({ orderToken: token }, {}, callbacks);Where you register callbacks depends on your storefront. The plugin settings cover some callbacks, not all of them.
| Storefront | Where callbacks go |
|---|---|
| Your own storefront code | The third argument of BoltCheckout.configure. See Web checkout. |
| BigCommerce | BoltCheckout.setClientCustomCallbacks(callbacks). See BigCommerce callbacks. |
| Adobe Commerce | The Bolt plugin's Advanced options, in fields such as Tracking: onCheckoutStart |
| WooCommerce | The Bolt plugin's settings, in fields such as Javascript event: onCheckoutStart |
Callbacks
| Callback | Arguments | When Bolt calls it |
|---|---|---|
check() | None | The shopper tries to open checkout. Return true, or a promise of true, to open it. Return false to keep it closed. Checkout also stays closed if a returned promise takes longer than 10 seconds. |
onCheckoutStart() | None | Checkout opened and shows its first step. |
onEmailEnter(email) | email: the address | The shopper entered a valid email address or changed it, or logged in to their Bolt account. |
onCredentialsCheck({ email, recognized }) | email, and recognized: true when the shopper can log in to a Bolt account with that email | Bolt checked the email the shopper entered. Also called with recognized: true when the shopper opens checkout already logged in. |
onShippingDetailsComplete(address) | address: the shipping address, with fields such as first_name, last_name, street_address1, locality, region, postal_code, country_code, phone, and email. Missing for Apple Pay. | The shopper completed the shipping address. Multi-step checkout only. |
onShippingOptionsComplete() | None | The shopper chose how the order ships. Multi-step checkout only. |
onPaymentSubmit(customFields) | customFields: the shopper's custom field responses, keyed by custom field public ID | The shopper selected the pay button. |
onUpsellPageShown(cart) | cart: the order's cart | A post-purchase offer appeared. Only when your checkout shows post-purchase offers. |
onUpsellDecision({ cart, decision }) | cart, and decision: accepted, declined, timed_out, or abandoned | The shopper responded to a post-purchase offer, or the offer timed out or was abandoned. |
success(transaction, callback) | transaction: the completed transaction. callback: call it when your code finishes. | Payment succeeded. Checkout waits up to 10 seconds for callback(), then continues without it. |
close() | None | The checkout modal closed. Not called when Bolt redirects the shopper to your order_received_url. |
onNotify(notifyEvent) | notifyEvent: see onNotify events | Checkout reported one of the events below. |
onNotify events
notifyEvent has an eventName, an eventSeverity of info or error, and, for some events, an eventMetadata object. Bolt adds events over time, so ignore names you don't recognize.
{
"eventName": "error_invalid_payment",
"eventSeverity": "error",
"eventMetadata": { "reasonCode": "payment_declined" }
}Info events
| Event | eventMetadata | When it fires |
|---|---|---|
info_account_creation_checked | None | The shopper checked the box to create a Bolt account. |
info_account_creation_unchecked | None | The shopper cleared the box to create a Bolt account. |
info_address_added | None | A logged-in shopper submitted a new or edited address. Also sent when the save fails. |
info_address_edited | None | Checkout finished updating the order's address, including after it loads a logged-in shopper's saved addresses. |
info_apm_selected | apm: the payment method, such as paypal, applepay, or klarna | The shopper selected an alternative payment method, or a saved one became the selected payment. |
info_checkbox_checked | checkbox_public_id: the custom field's public ID | Reports a checked custom field. Sent for each custom field whenever checkout changes step, and again when payment details are complete. |
info_checkbox_unchecked | checkbox_public_id | Reports an unchecked custom field. Sent for each custom field whenever checkout changes step. |
info_checkout_transition | nextStep: the step checkout moves to, such as shipping_method, payment, or logged_in_summary | Checkout moved to another step. |
info_custom_field_submitted | customFieldId: the custom field's external ID. value: the response. | A guest continued from the shipping address step to the delivery step, or a logged-in shopper started payment. Sent once for each custom field. Guests in a checkout without a separate delivery step don't send it. |
info_delivery_option_selected | cart, and shippingTier: the delivery option's name | The shopper selected a delivery option. |
info_delivery_option_submitted | cart, shippingTier | The shopper continued from the delivery step to payment. |
info_discount_removed | discountCode, and discountAmount when checkout knows it | The shopper removed a coupon or other discount. Not sent for gift cards. |
info_discount_successful | discountCode, and discountAmount when checkout knows it | A coupon or other discount applied. |
info_giftcard_successful | None | A gift card applied. |
info_payment_processing | None | Checkout started authorizing the payment. |
info_payment_type_added | None | The shopper chose to add a new card. |
info_payment_type_edited | None | The shopper deleted a saved card. |
info_payment_type_selected | None | A card became the selected payment, whether the shopper chose it or checkout selected it by default. |
webview_link_clicked | url | The shopper selected a link in checkout running inside a WebView. Checkout doesn't open the link; open url from your app. |
discountAmount has amount, currency, and currency_symbol, with amount in the currency's minor unit, such as cents. cart is the cart as checkout shows it.
Bolt can turn off info_checkout_transition, info_address_edited, info_checkbox_checked, and info_checkbox_unchecked for a division. If you don't receive them, contact Bolt support.
Error events
| Event | eventMetadata | When it fires |
|---|---|---|
error_discount_unsuccessful | None | A coupon or other discount didn't apply. |
error_giftcard_unsuccessful | None | A gift card didn't apply, or couldn't be removed. |
error_invalid_address | None | Checkout showed an error on a shipping address field, or the shipping address is incomplete. |
error_invalid_email | None | Checkout showed an error on the email field. |
error_invalid_name | None | Checkout showed an error on the shipping first or last name field. |
error_invalid_payment | reasonCode: payment_declined, duplicate_transaction, payment_method_not_supported, or bot_check_failed. Missing when saved payment methods fail to load. | A payment attempt failed, or the shopper's saved payment methods didn't load. Every card or issuer decline reports payment_declined. |
error_login_unsuccessful | None | A login code couldn't be sent or verified, the shopper's email or phone failed validation, or the shopper reached a rate limit. |
error_remove_discount_unsuccessful | None | A discount couldn't be removed. |
error_shipping | None | A logged-in shopper's saved addresses, or the delivery options, didn't load. |
error_tax | None | Tax couldn't be calculated. |
SSO sign-in modal
account.js opens Bolt's sign-in modal for SSO Commerce. When a shopper logs in with a verification code, the modal posts window messages to your page as JSON strings. It doesn't call onNotify or any other callback, so listen for message events on window.
These window messages are not a stable interface. Bolt can change or remove them at any time, including in ways that break code listening for them. Ignore fields you don't expect, and don't make sign-in or checkout depend on them.
Accept messages only from Bolt's sign-in frame: https://connect.boltapp.com in production and https://connect-sandbox.boltapp.com in sandbox. That is not the host that serves account.js, which redirects to account.boltapp.com. If your page loads account.js from a bolt.com host, the frame and its messages use https://connect.bolt.com or https://connect-sandbox.bolt.com instead.
Bolt sends these messages only to pages on your division's Trusted Domains, set in the Merchant Dashboard. A page on any other origin, such as www.example.com when only example.com is listed, receives none.
const BOLT_ORIGIN = "https://connect.boltapp.com";
window.addEventListener("message", (event) => {
if (event.origin !== BOLT_ORIGIN || typeof event.data !== "string") return;
let message;
try {
message = JSON.parse(event.data);
} catch {
return;
}
if (message.type !== "onNotify") return;
const { eventName, eventMetadata } = message.notifyEvent;
if (eventName === "login_outcome") {
window.dataLayer?.push({ event: "bolt_sso_login", outcome: eventMetadata.outcome });
}
});Each message has this shape:
{
"type": "onNotify",
"notifyEvent": {
"eventName": "login_outcome",
"eventSeverity": "info",
"eventMetadata": { "outcome": "SUCCESS" }
}
}| Event | eventSeverity | eventMetadata | When it fires |
|---|---|---|---|
login_attempted | info | email: the email the shopper entered to sign in | The shopper continued to the verification-code screen. Retrying a code on that screen sends no new event. Going back and continuing again, with the same or a different email, sends a new one. |
login_outcome | info, or error for FAILED | outcome: SUCCESS, FAILED, or ABANDONED | SUCCESS: Bolt accepted the code, before any platform login or redirect. FAILED: Bolt rejected a code; each rejected retry sends one. ABANDONED: the shopper closed the modal without logging in, including after a rejected code or after going back. |
- One login can send several
login_attemptedandFAILEDevents, then at most oneSUCCESSorABANDONED. Nothing follows either of those. - No outcome is sent when the shopper goes back from the code screen or leaves the page with the modal open, or for a login response that arrives after the modal closed.
- These events cover verification-code login only, not registration, social login, or dashboard login.
login_attemptedcarries the shopper's email, and any script on your page can read window messages, so treat it as shopper data. No message carries a verification code or token.
Embedded API
embed.js emits events on the Bolt object when shoppers log in and when Bolt checks their accounts. Call Bolt.initialize first: Bolt.on and Bolt.once throw an error before it.
Bolt.on(eventName: string, callback: (payload: any) => void, options?: { replayLast?: boolean }): () => void;
Bolt.once(eventName: string, callback: (payload: any) => void): () => void;Bolt.oncallscallbackevery time the event fires.Bolt.oncecalls it the next time only.- Both return a function that removes the listener.
- With
replayLast: true,Bolt.onalso runs the callback right away with the event's latest payload, if the event already fired on this page. Don't passreplayLasttoBolt.once: when the event already fired, it throws an error instead of running the callback.
Bolt.initialize("YOUR_PUBLISHABLE_KEY");
// Runs on every successful login.
const stopListening = Bolt.on("login_succeeded", ({ result }) => {
sendAuthorizationCodeToServer(result.authorizationCode); // your function
});
// Runs once, the next time the shopper logs out.
Bolt.once("logout", () => {
showSignedOutHeader(); // your function
});
// Later, stop listening for logins.
stopListening();| Event | Payload | When it fires |
|---|---|---|
account_check_complete | { email, result }: result is true when the email has a Bolt account | Bolt finished checking an email the shopper entered. |
auto_authorize_complete | { email, result }: result is the login result or an Error | A login that email detection started has ended. |
forgot_password_continue | { email, error } | The shopper selected the element you attached with context: "forgot_password", and Bolt didn't log them in. Continue with your own password reset. email is empty when no valid email was entered. When the login fails, the event fires twice, first with the email and then with an empty email, so start only one reset. |
login | The shopper's email, as a string | The shopper logged in, or Bolt.helpers.checkShopper() found an active Bolt session. |
login_complete | { email, result, loginContext }: result is the login result or an Error | A login attempt ended, whether it succeeded or failed. |
login_failed | { email, result, loginContext }: result is an Error | A login attempt failed. |
login_modal_closed | { context } | The login modal closed after a login attempt, for any reason. |
login_modal_dismissed | { context } | The shopper closed the login modal without logging in. |
login_succeeded | { email, result, loginContext }: result has authorizationCode and scope | A login attempt succeeded. Exchange authorizationCode on your server with Bolt OAuth. |
logout | {} | Bolt.helpers.logout() logged the shopper out. |
mount_failed | { component, email, context, reason } | mountPasswordlessLoginButton() couldn't show the login button. component is login_button. reason is Invalid email, No account found in the checkout context, or an error message. |
context and loginContext are the context you gave the login modal: checkout, sign_in, register, pre_checkout, or forgot_password.
Events kept for older integrations
These still fire. Use the newer event in new code.
| Event | Payload | Use instead |
|---|---|---|
authorize_complete | { email, result } | login_complete. Fires with every login_complete, and when the older authorization component finishes. |
auto_account_check_complete | { email, result }: result is a boolean or an Error | account_check_complete. This event is deprecated. |
authorize_modal_closed | { context: "checkout" } | login_modal_closed. Sent only by the older authorization component. |
Components report their own events through the component's on method, such as the payment fields' error event and the account checkbox's change event. See Payment fields and Account checkbox.