Skip to main content

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 PointDescription
Checkout::RenderBeforeBefore the page header
Checkout::RenderAfterAfter the page footer
Checkout::Head::RenderAfterAfter the page head
Checkout::FilledInformation::RenderAfterAfter the filled-in information card
Checkout::SpecialInstruction::RenderAfterAfter the special instructions
Checkout::Summary::RenderBeforeBefore the order summary
Checkout::Navigate::RenderBeforeBefore the navigation bar
Checkout::Navigate::RenderAfterAfter the navigation bar
Checkout::ContactInformation::RenderBeforeBefore the contact information module
Checkout::ContactInformation::RenderAfterAfter the contact information module
Checkout::ShippingLinesTitle::RenderBeforeBefore the shipping line title
Checkout::ShippingLinesTitle::RenderAfterAfter the shipping line title
Checkout::ShippingList::RenderAfterAfter the shipping list
Checkout::ProductList::RenderBeforeBefore the product list
Checkout::ProductList::RenderAfterAfter the product list
Checkout::Reductions::RenderBeforeBefore the discounts/gift cards
Checkout::Reductions::RenderAfterAfter the discounts/gift cards
Checkout::SectionPayment::RenderBeforeBefore the payment section
Checkout::SectionPayment::RenderAfterAfter the payment section

Thank-You Page

Extension PointDescription
Checkout::ThankyouHeader::RenderBeforeBefore the thank-you page header
Checkout::ThankyouContent::RenderBeforeBefore the thank-you page content area

Symmetry of extension points: Some modules only provide either RenderBefore or RenderAfter (e.g., ShippingList only has RenderAfter). 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 loading timing

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 like Decimal.js to 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): component is 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 like createElement / textContent instead.

Multiple calls to the same extension point: The same extensionPoint can be extend-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 by shoplazza-cli at build time. During the bundling phase, the CLI replaces the import './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.html as an assembly entry. It will not be recognized inside <script> tags or in JS files.
  • Imported HTML fragments should not contain further import directives to avoid recursion.
  • For simple content or scenarios requiring dynamic HTML generation, you can skip template files and directly pass concatenated strings to component in index.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 budget

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.