Checkout Extension Reference
This page is a reference manual for Checkout Extension: all extension points, CheckoutAPI data interfaces, the extend function, and the HTML template mechanism. For the development workflow, see Create a Checkout Extension. For practical scenarios, see Checkout Extension Recipes.
Extension Points
Extension points define where custom content is inserted into the page. Specify the corresponding name in the extensionPoint field of extend(), and the content is rendered at that location.
Checkout Page
| Extension Point | Description |
|---|---|
Checkout::RenderBefore | Before the page header |
Checkout::RenderAfter | After the page footer |
Checkout::Head::RenderAfter | After the page head |
Checkout::FilledInformation::RenderAfter | After the filled-in information card |
Checkout::SpecialInstruction::RenderAfter | After the special instructions |
Checkout::Summary::RenderBefore | Before the order summary |
Checkout::Navigate::RenderBefore | Before the navigation bar |
Checkout::Navigate::RenderAfter | After the navigation bar |
Checkout::ContactInformation::RenderBefore | Before the contact information module |
Checkout::ContactInformation::RenderAfter | After the contact information module |
Checkout::ShippingLinesTitle::RenderBefore | Before the shipping line title |
Checkout::ShippingLinesTitle::RenderAfter | After the shipping line title |
Checkout::ShippingList::RenderAfter | After the shipping list |
Checkout::ProductList::RenderBefore | Before the product list |
Checkout::ProductList::RenderAfter | After the product list |
Checkout::Reductions::RenderBefore | Before the discounts/gift cards |
Checkout::Reductions::RenderAfter | After the discounts/gift cards |
Checkout::SectionPayment::RenderBefore | Before the payment section |
Checkout::SectionPayment::RenderAfter | After the payment section |
Thank-You Page
| Extension Point | Description |
|---|---|
Checkout::ThankyouHeader::RenderBefore | Before the thank-you page header |
Checkout::ThankyouContent::RenderBefore | Before the thank-you page content area |
Symmetry of extension points: Some modules only provide either
RenderBeforeorRenderAfter(e.g.,ShippingListonly hasRenderAfter). This is because the other side is directly adjacent to an enclosing title or lacks a clear boundary, so injecting content there could cause layout issues.
CheckoutAPI Reference
CheckoutAPI is mounted on window.CheckoutAPI, providing read access to checkout data and event listening capabilities.
CheckoutAPI is only available after the page has fully loaded. Accessing window.CheckoutAPI directly may return undefined. You should wait for it to be mounted before calling it. It is recommended to use setTimeout with a maximum retry count and polling interval (approximately 5 seconds). See the mount function implementation in the "API calls and event listening" section of the recipes. Using requestAnimationFrame is not recommended, as busy waiting at 60fps consumes CPU on the checkout page.
Order Information (store)
interface OrderInfo {
currencyCode: string; // Checkout currency, e.g. "USD"
currencySymbol: string; // Currency symbol, e.g. "$"
alreadyPaymentLines: AlreadyPaymentLines;
failCode: string;
id: string;
status: OrderStatus;
checkoutStatus: string;
financialStatus: string;
orderNo: string;
cancelReason: string;
exceptionError?: string; // Thank-you page only
exceptionErrorMessage?: string; // Thank-you page only
additionalPrices?: AdditionalPrice[];
}
type OrderStatus = 'opened' | 'placed' | 'cancelled' | 'finished';
// Get order information
CheckoutAPI.store.getOrderInfo(): OrderInfo;
// Get order status
CheckoutAPI.store.getOrderStatus(): OrderStatus;
// Get referral information
CheckoutAPI.store.getReferInfo(): ReferInfo;
Product Information (summary)
interface UIProduct {
id: string;
variantId: string;
productTitle: string;
properties: ProductItem['properties'];
discountApplications: ProductItem['discountApplications'];
options: ProductItem['options'];
isFreeGift: boolean;
quantity: ProductItem['quantity'];
linePrice: ProductItem['linePrice'];
discountTotal?: ProductItem['discountTotal'];
finalLinePrice?: ProductItem['finalLinePrice'];
compareAtPrice: ProductItem['compareAtPrice'];
price: ProductItem['price'];
coverUrl: string;
}
// Get product list (line items including the properties field)
CheckoutAPI.summary.getProductList(): UIProduct[];
Price Information (store)
interface CheckoutPrices {
subtotalPrice: string;
shippingPrice: string;
taxPrice: string;
discountCodePrice: string;
discountPrice: string;
totalPrice: string;
discountLineItemPrice: string;
totalTipReceived: string;
discountShippingPrice: string;
giftCardPrice: string;
paymentDue: string; // Amount due
paidTotal: string;
discountSubTotal?: string;
shippingTaxTotal?: string;
allTaxTotal?: string;
paymentDiscountTotal?: string;
prePaymentAmount?: string;
additionalPrices?: AdditionalPrice[];
}
// Get price information
CheckoutAPI.store.getPrices(): CheckoutPrices;
// Listen for price changes
CheckoutAPI.store.onPricesChange(cb: (prices: CheckoutPrices) => void): void;
// Remove price change listener
CheckoutAPI.store.removePricesChangeCb(cb: (prices: CheckoutPrices) => void): void;
Price field format: All price fields are strings representing decimal numbers in the primary unit, e.g.,
"10.99"(10.99 USD), not the smallest unit (not"1099"cents). For calculations, it is recommended to use a library likeDecimal.jsto avoid JavaScript floating-point errors.
User Information (user)
// Check if user is logged in
CheckoutAPI.user.isLogin(): boolean;
// Redirect to login page, optionally with additional return URL parameters
CheckoutAPI.user.doLogin(returnUrlSearchParams?: Record<string, string>): void;
// Redirect to registration page
CheckoutAPI.user.doRegister(): void;
// Logout
CheckoutAPI.user.doLogout(): Promise<void>;
// Get logged-in user information
CheckoutAPI.user.getUserInfo(): UserInfo;
Address Information (address)
interface AddressValues {
id?: string;
firstName: string;
lastName: string;
countryCode: string;
country: string;
provinceCode: string;
province: string;
area: string;
city: string;
address: string;
address1: string;
zip: string; // Postal code
cpf?: string; // Tax ID
taxText?: string; // Tax ID label
idNumber?: string; // ID number
idNumberText?: string; // ID number label
company: string;
latitude?: string;
longitude?: string;
phone: string;
emailOrPhone: string;
email: string;
phoneAreaCode: string;
// Custom address fields may be added for different countries/regions (e.g., different tax IDs).
// When reading only the standard fields above, you can ignore these.
[key: string]: string | undefined;
}
// Get shipping address
CheckoutAPI.address.getShippingAddress(): AddressValues;
// Listen for shipping address changes (the callback receives a patch of changed fields, not the full address object)
CheckoutAPI.address.onShippingAddressChange(cb: (patch: Partial<AddressValues>) => void): void;
// Remove shipping address change listener
CheckoutAPI.address.removeShippingAddressChangeCb(cb: (patch: Partial<AddressValues>) => void): void;
Step Control (step)
type CheckoutStep = 'contact_information' | 'shipping_method' | 'payment_method';
// Get current step
CheckoutAPI.step.getStep(): CheckoutStep;
// Navigate to contact information step
CheckoutAPI.step.stepNavToInformation(): Promise<void>;
// Navigate to shipping information step
CheckoutAPI.step.stepNavToShipping(): Promise<void>;
// Navigate to payment information step
CheckoutAPI.step.stepNavToPayment(): Promise<void>;
// Listen for step changes
CheckoutAPI.step.onStepChange(cb: () => void): void;
// Remove step change listener
CheckoutAPI.step.removeStepChangeCb(cb: () => void): void;
// Navigate to a specific URL
CheckoutAPI.step.locationHref(url: string): void;
// Go to home page
CheckoutAPI.step.goToHomePage(): void;
extend function and HTML template
extend function
extend is the core function for registering content to an extension point. It is imported from shoplazza-extension-ui:
import { extend } from 'shoplazza-extension-ui';
extend({
extensionPoint: 'Checkout::Navigate::RenderBefore',
component: '<h1>Hello, Shoplazza!</h1>',
});
component accepts an HTML string and renders it at the corresponding extension point.
⚠️ Security Note (XSS Risk):
componentis a directly rendered HTML string. Do not concatenate unsanitized user input or external API return values into it to avoid XSS injection. For any dynamic content, perform HTML escape first, or use DOM APIs likecreateElement/textContentinstead.Multiple calls to the same extension point: The same
extensionPointcan beextend-ed multiple times. Content will be appended in call order, not overwritten.
HTML template
For complex content, we recommend splitting HTML into separate files. The scaffolding generates the following file structure by default:
src/index.html (optional, assembly entry):
<div>
import './style.html'
import './content.html'
import './script.html'
</div>
import './xxx.html'is not ES Module syntax. It is a text concatenation directive recognized byshoplazza-cliat build time. During the bundling phase, the CLI replaces theimport './xxx.html'line with the actual content of./xxx.html(inlined in order of appearance), rather than loading it dynamically at runtime.
- This syntax can only be used at the top level of
src/index.htmlas an assembly entry. It will not be recognized inside<script>tags or in JS files.- Imported HTML fragments should not contain further
importdirectives to avoid recursion.- For simple content or scenarios requiring dynamic HTML generation, you can skip template files and directly pass concatenated strings to
componentinindex.js.
src/style.html (optional, styles):
<style>
.my-block {
padding: 12px;
background: #f5f5f5;
}
</style>
src/content.html (optional, page content):
<div class="my-block">
<h2>Hello, Shoplazza!</h2>
</div>
src/script.html (optional): Scaffolding placeholder. To write scripts within an HTML template fragment, use a regular <script> tag:
<script>
document.querySelector('.my-block').addEventListener('click', function() {
window.CheckoutAPI.step.goToHomePage();
});
</script>
You can also skip HTML templates entirely and construct HTML strings directly in index.js for component. This suits simple content or dynamic generation.
Checkout page performance directly impacts conversion rate. Keep your extension JS/CSS as lean as possible: aim for < 30KB gzipped per extension, avoid large dependencies, and prefer passive approaches like setTimeout / IntersectionObserver over high-frequency polling.