--- name: checkout-customization description: Customize Shopify checkout with UI extensions and functions. Use this skill for building checkout UI extensions, adding custom fields, implementing payment customizations, creating post-purchase experiences, and extending customer accounts. Covers Checkout UI Extensions API and checkout branding. license: MIT compatibility: Requires Shopify CLI, Shopify Plus or Checkout Extensibility, and a Partner account metadata: author: shopify-agent-skills version: "1.0" shopify-api-version: "2025-01" --- # Checkout Customization ## When to use this skill Use this skill when: - Building checkout UI extensions - Adding custom fields to checkout - Implementing payment customizations - Creating post-purchase upsells - Extending customer account pages - Customizing the checkout experience - Adding custom validation logic ## Overview Checkout customization uses extensions that are: - **Upgrade-safe** - Work with Shop Pay and new features - **Performant** - Run in a sandboxed environment - **Secure** - Limited access for security ### Extension Types | Type | Description | | --------------------- | ---------------------------- | | **Checkout UI** | Add custom UI to checkout | | **Post-purchase** | Upsells after order | | **Customer Accounts** | Extend account pages | | **Thank You** | Customize order confirmation | | **Order Status** | Extend order tracking | ## Getting Started ### 1. Create Checkout Extension ```bash # In an existing app shopify app generate extension # Select: Checkout UI ``` ### 2. Extension Structure ``` extensions/ └── checkout-ui/ ├── src/ │ └── Checkout.jsx ├── locales/ │ └── en.default.json └── shopify.extension.toml ``` ### 3. Configuration ```toml # shopify.extension.toml api_version = "2025-01" [[extensions]] type = "ui_extension" name = "Custom Checkout" handle = "custom-checkout" [[extensions.targeting]] module = "./src/Checkout.jsx" target = "purchase.checkout.block.render" ``` ## Checkout UI Extensions ### Basic Extension ```jsx // src/Checkout.jsx import { reactExtension, Banner, useApi, useTranslate, } from "@shopify/ui-extensions-react/checkout"; export default reactExtension("purchase.checkout.block.render", () => ( )); function Extension() { const translate = useTranslate(); return ( Thank you for shopping with us! ); } ``` ### Extension Targets Common checkout targets: ```jsx // Before shipping options "purchase.checkout.shipping-option-list.render-before"; // After shipping options "purchase.checkout.shipping-option-list.render-after"; // Payment method "purchase.checkout.payment-method-list.render-before"; // Order summary "purchase.checkout.cart-line-list.render-after"; // Static render (header/footer) "purchase.checkout.header.render-after"; "purchase.checkout.footer.render-after"; // Block render (anywhere in checkout) "purchase.checkout.block.render"; // Delivery address "purchase.checkout.delivery-address.render-before"; ``` ### Using Checkout Data ```jsx import { useCartLines, useTotalAmount, useShippingAddress, useBuyerJourney, useCustomer, useDiscountCodes, } from "@shopify/ui-extensions-react/checkout"; function Extension() { const cartLines = useCartLines(); const totalAmount = useTotalAmount(); const shippingAddress = useShippingAddress(); const customer = useCustomer(); const discountCodes = useDiscountCodes(); const total = totalAmount?.amount; const itemCount = cartLines.reduce((sum, line) => sum + line.quantity, 0); return ( Items in cart: {itemCount} Total: ${total} {customer && Welcome back, {customer.firstName}!} ); } ``` ### UI Components ```jsx import { Banner, BlockStack, InlineStack, Text, Button, Checkbox, TextField, Select, Image, Divider, Heading, Link, View, Grid, Icon, } from "@shopify/ui-extensions-react/checkout"; function Extension() { const [checked, setChecked] = useState(false); const [note, setNote] = useState(""); return ( Gift Options This is a gift {checked && ( )} ); } ``` ### Custom Fields with Metafields ```jsx import { useApplyMetafieldsChange, useMetafield, } from "@shopify/ui-extensions-react/checkout"; function GiftMessage() { const [message, setMessage] = useState(""); const applyMetafieldsChange = useApplyMetafieldsChange(); const handleChange = async (value) => { setMessage(value); await applyMetafieldsChange({ type: "updateMetafield", namespace: "custom", key: "gift_message", valueType: "string", value, }); }; return ( ); } ``` ### Buyer Journey Intercept Block checkout progression with validation: ```jsx import { useBuyerJourneyIntercept } from "@shopify/ui-extensions-react/checkout"; function AgeVerification() { const [verified, setVerified] = useState(false); useBuyerJourneyIntercept(({ canBlockProgress }) => { if (!verified && canBlockProgress) { return { behavior: "block", reason: "Age verification required", errors: [ { message: "Please verify your age to continue", }, ], }; } return { behavior: "allow" }; }); return ( I confirm I am 21 or older ); } ``` ## Post-Purchase Extensions ### Create Post-Purchase Extension ```bash shopify app generate extension # Select: Post-purchase UI ``` ### Post-Purchase Upsell ```jsx // src/PostPurchase.jsx import { extend, render, useExtensionInput, BlockStack, Button, Text, Image, Heading, CalloutBanner, Layout, TextContainer, } from "@shopify/post-purchase-ui-extensions-react"; extend("Checkout::PostPurchase::ShouldRender", async ({ storage }) => { // Decide whether to show post-purchase const upsellProduct = await fetchUpsellProduct(); await storage.update({ upsellProduct }); return { render: true }; }); render("Checkout::PostPurchase::Render", () => ); function App() { const { storage, done, calculateChangeset, applyChangeset } = useExtensionInput(); const { upsellProduct } = storage.initialData; const handleAccept = async () => { const changeset = await calculateChangeset({ changes: [ { type: "add_variant", variantId: upsellProduct.variantId, quantity: 1, }, ], }); await applyChangeset(changeset.token); done(); }; const handleDecline = () => { done(); }; return ( Add this item to your order at 20% off {upsellProduct.title} ${upsellProduct.price} (20% off) ); } ``` ## Customer Account Extensions ```jsx // Extend customer account pages import { reactExtension, Page, Card, BlockStack, Text, } from "@shopify/ui-extensions-react/customer-account"; export default reactExtension("customer-account.page.render", () => ( )); function CustomAccountPage() { return ( Your Points: 500 Earn points with every purchase! ); } ``` ## Localization ```json // locales/en.default.json { "welcomeMessage": "Welcome to checkout", "giftLabel": "Gift options", "verifyAge": "I confirm I am 21 or older" } // locales/fr.json { "welcomeMessage": "Bienvenue au paiement", "giftLabel": "Options cadeau", "verifyAge": "Je confirme avoir 21 ans ou plus" } ``` ```jsx import { useTranslate } from "@shopify/ui-extensions-react/checkout"; function Extension() { const translate = useTranslate(); return {translate("welcomeMessage")}; } ``` ## Network Requests ```jsx import { useApi } from "@shopify/ui-extensions-react/checkout"; function Extension() { const { sessionToken } = useApi(); const fetchData = async () => { const token = await sessionToken.get(); const response = await fetch("https://your-app.com/api/data", { headers: { Authorization: `Bearer ${token}`, }, }); return response.json(); }; // Use in useEffect or event handler } ``` ## Testing ### Local Development ```bash # Start app with preview shopify app dev # Extensions will load in checkout preview ``` ### Testing in Checkout Editor 1. Go to Shopify admin > Settings > Checkout 2. Click "Customize" 3. Add your extension block 4. Preview changes ## Best Practices 1. **Keep extensions fast** - Minimize API calls 2. **Handle errors gracefully** - Show user-friendly messages 3. **Support localization** - Use translation files 4. **Test on mobile** - Checkout is often mobile 5. **Follow design guidelines** - Match Shopify's checkout style 6. **Use progressive enhancement** - Graceful degradation ## Resources - [Checkout UI Extensions](https://shopify.dev/docs/api/checkout-ui-extensions) - [Checkout UI Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Post-Purchase Extensions](https://shopify.dev/docs/apps/build/checkout/post-purchase) - [Customer Account Extensions](https://shopify.dev/docs/api/checkout-ui-extensions/extension-targets-overview#customer-account-targets) - [Extension Targets Reference](https://shopify.dev/docs/api/checkout-ui-extensions/extension-targets-overview) For backend logic, see the [shopify-functions](../shopify-functions/SKILL.md) skill.