Shopify CLI: How to Create a Customer Account UI Extension

Customer Account UI Extensions let you add custom React components directly into Shopify’s native customer account interface — the order history page, order detail page, profile page, and more. No Liquid hacks, no iframes, just first-class extensions that feel native to the Shopify experience.

This guide walks through the full workflow: CLI setup, creating the extension scaffold, writing components with the customer-account-ui-extensions library, local dev preview, and deployment.

Key Takeaway:

Prerequisites

  • Node.js 18+ and npm/pnpm
  • Shopify CLI 3.x: npm install -g @shopify/cli
  • A Shopify Partner account and a development store
  • A Shopify app (existing or new) — extensions live inside apps

Step 1: Create or Navigate to Your Shopify App

Create a new app (if needed)

shopify app init my-customer-app
cd my-customer-app

Select your preferred language (JavaScript/TypeScript) and template (Remix is recommended for new apps).

Generate the Customer Account UI Extension

shopify app generate extension

Select Customer account UI from the extension type list. Give it a name like loyalty-dashboard. Select JavaScript or TypeScript.

Step 2: Understand the Extension Structure

After generation, your extension lives at extensions/loyalty-dashboard/ with this structure:

extensions/loyalty-dashboard/
├── shopify.extension.toml    # Extension configuration
├── src/
│   └── CustomerAccountBlock.tsx  # Main extension component
├── package.json
└── tsconfig.json

shopify.extension.toml

name = "Loyalty Dashboard"
handle = "loyalty-dashboard"
type = "ui_extension"

[[extensions.targeting]]
module = "./src/CustomerAccountBlock.tsx"
target = "customer-account.order-index.block.render"

[settings]
  [[settings.fields]]
  key = "loyalty_api_url"
  type = "single_line_text_field"
  name = "Loyalty API URL"

Step 3: Write the Extension Component

Extensions use the @shopify/ui-extensions-react/customer-account package for components. These are Shopify’s own UI primitives — not HTML elements:

// src/CustomerAccountBlock.tsx
import {
  reactExtension,
  useApi,
  BlockStack,
  InlineStack,
  Text,
  Button,
  Divider,
  SkeletonText,
} from '@shopify/ui-extensions-react/customer-account';

export default reactExtension(
  'customer-account.order-index.block.render',
  () => <LoyaltyDashboard />
);

function LoyaltyDashboard() {
  const { customer } = useApi();
  const [points, setPoints] = React.useState<number | null>(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    // Fetch loyalty points from your backend
    customer.id.then(async (customerId) => {
      const response = await fetch(
        `https://your-app.myshopify.com/loyalty/${customerId}`
      );
      const data = await response.json();
      setPoints(data.points);
      setLoading(false);
    });
  }, []);

  if (loading) {
    return (
      <BlockStack spacing="base">
        <SkeletonText />
        <SkeletonText />
      </BlockStack>
    );
  }

  return (
    <BlockStack spacing="base" border="base" cornerRadius="base" padding="base">
      <Text size="large" emphasis="bold">Your Loyalty Points</Text>
      <Divider />
      <InlineStack spacing="base" blockAlignment="center">
        <Text size="extraLarge" emphasis="bold">{points}</Text>
        <Text tone="subdued">points available</Text>
      </InlineStack>
      <Button to="/loyalty">View Rewards</Button>
    </BlockStack>
  );
}

Step 4: Available Extension Targets

Choose where your extension renders by setting the target in your TOML:

  • customer-account.order-index.block.render — on the order list page
  • customer-account.order-status.block.render — on the order detail/status page
  • customer-account.profile.block.render — on the customer profile page
  • customer-account.page.render — render a full custom page (accessed via navigation link)

You can target multiple locations by adding multiple [[extensions.targeting]] blocks in your TOML.

Step 5: Accessing Customer Data via useApi()

The useApi() hook exposes customer context and app utilities:

const {
  customer,           // Customer ID, email, tags
  orders,             // Order list data
  navigation,         // Navigate between pages
  storage,            // Local storage for the extension
  settings,           // Settings fields from shopify.extension.toml
  i18n,               // Internationalization utilities
  authenticatedFetch, // Authenticated fetch to your app backend
} = useApi();

Use authenticatedFetch instead of plain fetch when calling your app’s backend API — it automatically includes a session token that your backend can verify:

const { authenticatedFetch } = useApi();

const response = await authenticatedFetch('/api/loyalty-points');
const data = await response.json();

Step 6: Local Development Preview

shopify app dev

This starts the local dev server and provides a URL to preview the extension on your development store. You’ll see live reload as you edit component code. Open your dev store’s customer account, log in, and navigate to the target page — you’ll see your extension rendered inline.

Step 7: Deploy the Extension

# Build and upload the extension
shopify app deploy

# This will:
# 1. Build all extensions
# 2. Upload to Shopify's CDN
# 3. Create a new app version in your Partner Dashboard

After deploying, go to your Shopify Partner Dashboard → Apps → your app → Extensions, and verify the extension version is published. Merchants then activate it from their Shopify admin under Customer Accounts settings.

Real-World Use Cases

  • Loyalty points dashboard — show points balance and redemption options on the orders page
  • Return portal — embed a self-service returns flow on the order status page
  • Subscription management — show active subscriptions with pause/cancel actions on the profile page
  • Custom profile fields — collect additional customer data (birthday, preferences) stored as metafields
  • Wishlist display — show saved items with quick-add-to-cart on a custom account page

Frequently Asked Questions

A Customer Account UI Extension lets you add custom UI components to Shopify’s customer account pages (order history, profile, etc.) without modifying the Liquid template directly. Extensions are built with React and the customer-account-ui-extensions component library.

You write the extension in JavaScript or TypeScript using React via Shopify’s customer-account-ui-extensions runtime. You don’t pick an arbitrary framework — extensions render through Shopify’s Remote UI model using their provided component primitives, so the ‘framework’ is effectively React plus Shopify’s component library. TypeScript is recommended for the typed API surface.

No. Customer Account UI Extensions run in an isolated sandbox under Shopify’s Remote UI rendering model and communicate with the host via message passing. You build the UI from Shopify’s component primitives (BlockStack, Text, Button, and so on) — arbitrary HTML/CSS and third-party UI libraries like MUI or Tailwind won’t render. This keeps extensions native, secure, and consistent, at the cost of pixel-level styling control.

Customer Account UI Extensions work with all Shopify plans that use the new customer accounts (launched 2023). They’re available to apps in the Shopify App Store and custom apps. Shopify Plus enables additional extension targets.

Use the useApi() hook to get the extension’s API object, which exposes the authenticated context — customer info, the buyer’s order data, and an authenticatedFetch you can call against your app’s backend. Because the extension runs in a sandbox, you don’t query Shopify directly with secrets; sensitive calls go through authenticatedFetch to your server, which holds the credentials.

Available targets include: customer-account.order-index.block.render (order list), customer-account.order-status.block.render (order detail), customer-account.profile.block.render (profile page), and customer-account.page.render (custom full pages).

Run shopify app dev from your app directory. The CLI starts a development session, gives you a preview URL, and hot-reloads the extension as you edit. It connects to your development store so you can open the customer account area and see your extension rendered in its real target (order index, order detail, profile, and so on) without deploying.

Deploy using ‘shopify app deploy’ from your CLI. The extension is uploaded to Shopify’s CDN and associated with your app. Merchants activate it from the Shopify admin by enabling the app in their Customer Accounts settings.

Related Resources

Custom Shopify Development

End-to-end Shopify development including apps and extensions.

Learn More

Shopify Plus Development

Advanced Shopify Plus features including Functions and Checkout Extensibility.

Learn More

Shopify Headless Commerce

When to use the Storefront API vs. extensions for custom UX.

Learn More