Skip to main content

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

TargetLocation
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:
<!-- 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: 24px;
    padding: 16px;
    background: #f8f9fa;
    border-radius: 8px;
    margin-top: 16px;
  }
  .trust-badge {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    color: #666;
  }
  .trust-badge svg {
    width: 20px;
    height: 20px;
    color: #28a745;
  }
</style>

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

VariableDescription
--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

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.
Interactive extension component URLs must use HTTPS and be registered in your app’s allowed origins.
Checkout extensions cannot access credit card numbers or sensitive payment information.

Example: Gift Options Extension

A complete example with gift wrapping and message:
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.