Documentation Index Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
Checkout UI Extensions
Checkout UI extensions allow your app to add custom elements to the checkout flow. Use them to display trust badges, upsells, custom fields, delivery instructions, and more.
Extension Points
Checkout UI extensions render at specific points in the checkout:
┌─────────────────────────────────────────────┐
│ Cart Summary │
│ ┌───────────────────────────────────────┐ │
│ │ checkout.cart-line-list.render-after │ │
│ └───────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Contact Information │
│ ┌───────────────────────────────────────┐ │
│ │ checkout.contact.render-after │ │
│ └───────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Shipping Address │
│ ┌───────────────────────────────────────┐ │
│ │ checkout.shipping-address.render-after│ │
│ └───────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Shipping Methods │
│ ┌───────────────────────────────────────┐ │
│ │ checkout.shipping-method-list.render- │ │
│ │ after │ │
│ └───────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Payment Methods │
│ ┌───────────────────────────────────────┐ │
│ │ checkout.payment-method-list.render- │ │
│ │ after │ │
│ └───────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Order Summary │
│ ┌───────────────────────────────────────┐ │
│ │ checkout.order-summary.render-after │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
Available Targets
Target Location checkout.cart-line-list.render-afterAfter cart items list checkout.contact.render-afterAfter contact information checkout.shipping-address.render-afterAfter shipping address form checkout.shipping-method-list.render-afterAfter shipping options checkout.payment-method-list.render-afterAfter payment methods checkout.order-summary.render-afterAfter order summary checkout.header.render-afterAfter checkout header checkout.footer.render-beforeBefore checkout footer
Creating a Checkout Extension
1. Define the Extension Manifest
Add your checkout extension to app.json:
{
"handle" : "my-checkout-app" ,
"name" : "Checkout Enhancements" ,
"version" : "1.0.0" ,
"extensions" : {
"checkout_ui" : [
{
"handle" : "trust-badges" ,
"name" : "Trust Badges" ,
"target" : "checkout.payment-method-list.render-after" ,
"type" : "static"
},
{
"handle" : "upsell-products" ,
"name" : "Upsell Products" ,
"target" : "checkout.cart-line-list.render-after" ,
"type" : "dynamic"
},
{
"handle" : "delivery-instructions" ,
"name" : "Delivery Instructions" ,
"target" : "checkout.shipping-address.render-after" ,
"type" : "interactive"
}
]
}
}
2. Create the Extension Component
Checkout extensions can be static HTML, Liquid templates, or React components:
Static HTML
Liquid Template
React Component
<!-- trust-badges.html -->
< div class = "checkout-trust-badges" >
< div class = "trust-badge" >
< svg > <!-- secure icon --> </ svg >
< span > Secure Checkout </ span >
</ div >
< div class = "trust-badge" >
< svg > <!-- shipping icon --> </ svg >
< span > Free Returns </ span >
</ div >
< div class = "trust-badge" >
< svg > <!-- guarantee icon --> </ svg >
< span > Money-Back Guarantee </ span >
</ div >
</ div >
< style >
.checkout-trust-badges {
display : flex ;
justify-content : center ;
gap : 24 px ;
padding : 16 px ;
background : #f8f9fa ;
border-radius : 8 px ;
margin-top : 16 px ;
}
.trust-badge {
display : flex ;
align-items : center ;
gap : 8 px ;
font-size : 14 px ;
color : #666 ;
}
.trust-badge svg {
width : 20 px ;
height : 20 px ;
color : #28a745 ;
}
</ style >
<!-- upsell-products.aqua -->
{% if cart . total_price < 5000 %}
< div class = "checkout-upsell" >
< h4 > Add {{ 5000 | minus: cart . total_price | money }} more for free shipping! </ h4 >
< div class = "upsell-products" >
{% for product in collections [ 'bestsellers' ]. products limit: 3 %}
{% unless cart . items | map : 'product_id' | contains : product . id %}
< div class = "upsell-product" >
< img src = " {{ product . featured_image | image_url: width: 80 }} " alt = " {{ product . title }} " >
< div class = "upsell-info" >
< span class = "upsell-title" >{{ product . title }}</ span >
< span class = "upsell-price" >{{ product . price | money }}</ span >
</ div >
< button
class = "upsell-add"
data-variant = " {{ product . first_available_variant . id }} "
>
Add
</ button >
</ div >
{% endunless %}
{% endfor %}
</ div >
</ div >
{% endif %}
// delivery-instructions.jsx
import { useState } from 'react' ;
import { useCheckout , useCheckoutField } from '@launchmystore/checkout-ui-extensions-react' ;
export default function DeliveryInstructions () {
const checkout = useCheckout ();
const [ instructions , setInstructions ] = useCheckoutField ( 'delivery_instructions' );
const [ leaveAtDoor , setLeaveAtDoor ] = useState ( false );
const handleSave = () => {
checkout . updateAttributes ({
delivery_instructions: instructions ,
leave_at_door: leaveAtDoor
});
};
return (
< div className = "delivery-instructions" >
< h4 > Delivery Instructions </ h4 >
< label className = "checkbox-label" >
< input
type = "checkbox"
checked = { leaveAtDoor }
onChange = { ( e ) => setLeaveAtDoor ( e . target . checked ) }
/>
Leave at door if no one is home
</ label >
< textarea
placeholder = "Add any special delivery instructions..."
value = { instructions }
onChange = { ( e ) => setInstructions ( e . target . value ) }
maxLength = { 200 }
/>
< button onClick = { handleSave } > Save Instructions </ button >
</ div >
);
}
Installing Checkout Extensions
await fetch ( 'https://store.launchmystore.io/api/apps/install-extensions' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ accessToken } `
},
body: JSON . stringify ({
domainSlug: 'merchant-store' ,
appHandle: 'my-checkout-app' ,
checkout_ui: [
{
handle: 'trust-badges' ,
target: 'checkout.payment-method-list.render-after' ,
type: 'static' ,
content: '<div class="checkout-trust-badges">...</div>' ,
styles: '.checkout-trust-badges { ... }'
},
{
handle: 'upsell-products' ,
target: 'checkout.cart-line-list.render-after' ,
type: 'dynamic' ,
template: '{% if cart.total_price < 5000 %}...'
},
{
handle: 'delivery-instructions' ,
target: 'checkout.shipping-address.render-after' ,
type: 'interactive' ,
component_url: 'https://my-app.com/checkout/delivery-instructions.js'
}
]
})
});
Extension Types
Static Extensions
Pre-rendered HTML that doesn’t change based on checkout state:
{
"handle" : "trust-badges" ,
"type" : "static" ,
"content" : "<div>...</div>" ,
"styles" : ".class { ... }"
}
Dynamic Extensions
Liquid templates that render with checkout context:
{
"handle" : "free-shipping-progress" ,
"type" : "dynamic" ,
"template" : "{% assign remaining = 5000 | minus: cart.total_price %}..."
}
Interactive Extensions
React components with full interactivity:
{
"handle" : "gift-options" ,
"type" : "interactive" ,
"component_url" : "https://my-app.com/checkout/gift-options.js"
}
Checkout Context
Interactive extensions receive the checkout context:
interface CheckoutContext {
cart : {
items : CartItem [];
subtotal : number ;
total : number ;
discounts : Discount [];
};
customer : {
id : string ;
email : string ;
firstName : string ;
lastName : string ;
} | null ;
shippingAddress : Address | null ;
billingAddress : Address | null ;
shippingMethod : ShippingMethod | null ;
paymentMethod : string | null ;
attributes : Record < string , string >;
}
Checkout UI Hooks
The @launchmystore/checkout-ui-extensions-react package provides hooks:
useCheckout
Access the full checkout context:
import { useCheckout } from '@launchmystore/checkout-ui-extensions-react' ;
function MyExtension () {
const checkout = useCheckout ();
return (
< div >
< p > Subtotal: { checkout . cart . subtotal } </ p >
< p > Items: { checkout . cart . items . length } </ p >
</ div >
);
}
useCheckoutField
Read/write custom checkout attributes:
import { useCheckoutField } from '@launchmystore/checkout-ui-extensions-react' ;
function GiftMessage () {
const [ message , setMessage ] = useCheckoutField ( 'gift_message' );
return (
< textarea
value = { message || '' }
onChange = { ( e ) => setMessage ( e . target . value ) }
/>
);
}
useCart
Access cart data with update methods:
import { useCart } from '@launchmystore/checkout-ui-extensions-react' ;
function UpsellButton ({ variantId }) {
const cart = useCart ();
const handleAdd = async () => {
await cart . addItem ( variantId , 1 );
};
return < button onClick = { handleAdd } > Add to Order </ button > ;
}
Styling Guidelines
Checkout extensions should match the store’s checkout styling. Avoid aggressive colors or styles that conflict with the checkout design.
Use CSS Custom Properties
.my-extension {
font-family : var ( --checkout-font-family );
color : var ( --checkout-text-color );
background : var ( --checkout-background );
border-radius : var ( --checkout-border-radius );
}
.my-extension-button {
background : var ( --checkout-primary-color );
color : var ( --checkout-primary-text );
}
Available CSS Variables
Variable Description --checkout-font-familyCheckout font family --checkout-text-colorPrimary text color --checkout-muted-colorSecondary text color --checkout-backgroundSection background --checkout-border-colorBorder color --checkout-border-radiusBorder radius --checkout-primary-colorPrimary button color --checkout-primary-textPrimary button text --checkout-spacingStandard spacing unit
Security Considerations
No external scripts in static/dynamic extensions
Static and dynamic extensions cannot load external JavaScript. Use interactive extensions (React components) for custom JS.
All HTML in static extensions is sanitized. Inline event handlers (onclick, etc.) are stripped.
Component URLs must be HTTPS
Interactive extension component URLs must use HTTPS and be registered in your app’s allowed origins.
No access to payment data
Checkout extensions cannot access credit card numbers or sensitive payment information.
Example: Gift Options Extension
A complete example with gift wrapping and message:
GiftOptions.jsx
gift-options.css
import { useState } from 'react' ;
import { useCheckout , useCheckoutField } from '@launchmystore/checkout-ui-extensions-react' ;
export default function GiftOptions () {
const checkout = useCheckout ();
const [ isGift , setIsGift ] = useCheckoutField ( 'is_gift' );
const [ giftMessage , setGiftMessage ] = useCheckoutField ( 'gift_message' );
const [ giftWrap , setGiftWrap ] = useCheckoutField ( 'gift_wrap' );
const GIFT_WRAP_PRICE = 499 ; // $4.99
const handleGiftWrapChange = ( checked ) => {
setGiftWrap ( checked );
if ( checked ) {
checkout . addLineItem ({
type: 'service' ,
title: 'Gift Wrapping' ,
price: GIFT_WRAP_PRICE
});
} else {
checkout . removeLineItem ( 'gift_wrap_service' );
}
};
return (
< div className = "gift-options" >
< div className = "gift-options-header" >
< label className = "gift-checkbox" >
< input
type = "checkbox"
checked = { isGift || false }
onChange = { ( e ) => setIsGift ( e . target . checked ) }
/>
< span > This is a gift </ span >
</ label >
</ div >
{ isGift && (
< div className = "gift-options-body" >
< label className = "gift-wrap-option" >
< input
type = "checkbox"
checked = { giftWrap || false }
onChange = { ( e ) => handleGiftWrapChange ( e . target . checked ) }
/>
< span > Add gift wrapping (+$4.99) </ span >
</ label >
< div className = "gift-message-field" >
< label > Gift Message (optional) </ label >
< textarea
value = { giftMessage || '' }
onChange = { ( e ) => setGiftMessage ( e . target . value ) }
placeholder = "Enter a message for the recipient..."
maxLength = { 500 }
/>
< span className = "char-count" >
{ ( giftMessage || '' ). length } /500
</ span >
</ div >
</ div >
) }
</ div >
);
}
Debugging
Enable debug mode in your extension:
// In your component
if ( process . env . NODE_ENV === 'development' ) {
console . log ( 'Checkout context:' , checkout );
console . log ( 'Extension rendered at:' , target );
}
Check the browser console for extension errors and the Network tab for failed component loads.