Shopify Checkout UI Extensions
Before writing code
Fetch live docs:
- Fetch
https://shopify.dev/docs/apps/build/checkoutfor checkout extensions - Web-search
site:shopify.dev checkout ui extension targetsfor available targets - Web-search
site:shopify.dev checkout ui componentsfor UI primitives
What Are Checkout UI Extensions
Client-side extensions that add UI to Shopify's checkout:
- Render at specific extension targets (locations in checkout flow)
- Use Shopify's UI primitives (not Polaris, not HTML)
- Built with Preact and Remote DOM — sandboxed rendering
- Access checkout state via APIs (no direct DOM access)
Important: You cannot replace Shopify's checkout — only extend it at designated points.
Extension Targets
Locations where extensions can render:
Checkout Page
purchase.checkout.block.render— general block in checkoutpurchase.checkout.header.render-after— after checkout headerpurchase.checkout.footer.render-after— after checkout footerpurchase.checkout.contact.render-after— after contact infopurchase.checkout.shipping-option-list.render-after— after shipping optionspurchase.checkout.payment-method-list.render-after— after payment methodspurchase.checkout.actions.render-before— before pay button
Thank You Page
purchase.thank-you.block.render— block on thank-you page
Order Status Page
customer-account.order-status.block.render— block on order status
Post-Purchase
purchase.post-purchase.render— full-page post-purchase upsellpurchase.post-purchase.should-render— decide whether to show post-purchase
UI Primitives
Checkout extensions use Shopify's UI components (NOT Polaris, NOT HTML):
| Component | Purpose |
|---|---|
Banner |
Information/warning/error messages |
BlockStack |
Vertical layout |
Button |
Action buttons |
Checkbox |
Boolean input |
ChoiceList |
Radio/checkbox groups |
Divider |
Visual separator |
Form |
Form container |
Heading |
Section headings |
Icon |
Icons |
Image |
Images |
InlineStack |
Horizontal layout |
Link |
Navigation links |
Select |
Dropdown selection |
Text |
Text content |
TextBlock |
Block of text |
TextField |
Text input |
Extension Structure
extensions/checkout-ui/
├── src/
│ └── Checkout.tsx # Extension component
├── shopify.extension.toml # Configuration
├── locales/
│ └── en.default.json # Translations
└── package.json
Configuration
api_version = "2025-01"
[[extensions]]
name = "Custom Checkout Banner"
handle = "custom-checkout-banner"
type = "ui_extension"
[[extensions.targeting]]
module = "./src/Checkout.tsx"
target = "purchase.checkout.block.render"
Extension Component
import {
Banner,
useExtensionApi,
useCartLines,
useApplyCartLinesChange,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <CheckoutBanner />,
);
function CheckoutBanner() {
const { extension } = useExtensionApi();
const cartLines = useCartLines();
const applyCartLinesChange = useApplyCartLinesChange();
const itemCount = cartLines.reduce((sum, line) => sum + line.quantity, 0);
if (itemCount < 3) {
return (
<Banner status="info">
Add {3 - itemCount} more item(s) for free shipping!
</Banner>
);
}
return null;
}
Checkout APIs (Hooks)
| Hook | Purpose |
|---|---|
useCartLines() |
Current cart line items |
useApplyCartLinesChange() |
Modify cart lines |
useShippingAddress() |
Shipping address |
useBuyerJourney() |
Intercept checkout progression |
useAppMetafields() |
Read app metafields |
useCheckoutToken() |
Checkout session token |
useCurrency() |
Current currency |
useLocalizationCountry() |
Customer country |
useExtensionApi() |
Full extension API |
Best Practices
- Use Shopify UI primitives — never attempt raw HTML or Polaris components
- Keep checkout extensions minimal — do not slow down checkout
- Use
useBuyerJourney()to validate before checkout progression - Store extension configuration in metafields
- Support localization with locale files
- Test with
shopify app devand a development store checkout - Follow Shopify's checkout UX guidelines — do not distract from payment
Fetch the Shopify checkout UI extensions docs for exact component APIs, available hooks, and extension target names before implementing.