Building Shopify Thank You and Order Status Page Extensions: Complete Tutorial

After years of being limited to the checkout page, Shopify has finally launched checkout UI extensions for thank you and order status pages. This opens up entirely new possibilities for creating custom experiences throughout your customer’s entire journey.

I recently built my first thank-you page extension, and honestly, the process was smoother than I expected. Let me walk you through everything I learned, from setup to deployment.

Key Points You’ll Learn

  • How to create checkout UI extensions for thank you and order status pages
  • Setting up metafields to store custom product messages
  • Building a multi-target extension that works across checkout, thank you, and order status pages
  • Proper deployment and installation process
  • Why these extensions matter for your store’s customer experience

What Are Thank You and Order Status Page Extensions?

Before diving in, let’s clarify what we’re working with. The thank you page is what customers see immediately after placing an order. If they refresh that page or return to it later, they’ll see the order status page instead.

Previously, we couldn’t add custom UI to these pages through checkout extensibility. Now we can create meaningful touchpoints at these crucial moments in the customer journey.

Setting Up Your Extension Environment

Create the Metafield Structure

First, you’ll need to set up a metafield to store your custom messages:

  1. Go to Settings > Custom data in your Shopify admin
  2. Create a new metafield with these settings:
    • Name: “Checkout Message”
    • Type: Single line of text
    • Storefront access: Enabled (required for admin API queries)

Add Test Data

Navigate to your products and add a test message to one of them. I used “Uses 80% recycled materials” as an example, but this could be anything from “Batteries not included” to “Limited edition item.”

Building the Extension

Initialize Your Project

npm init @shopify/app@latest

Choose “Start by adding your first extension” to create an extension-only app. Once installed, generate your checkout UI extension:

npm run shopify app generate extension

Select Checkout UI and choose TypeScript React for the template.

Understanding Extension Targets

The key to making this work is understanding extension targets. Here’s what I discovered:

Target Types

Target Type Description Merchant Control
Blue targets (e.g., purchase.thank-you.block.render) Flexible placement - merchants can choose where to position Full control
Red targets (e.g., purchase.thank-you.cart-line-item.render-after) Fixed placement - renders in specific location Enable/disable only

For this tutorial, I chose purchase.thank-you.cart-line-item.render-after because it makes sense contextually - the message appears right after each product line item.

Code Implementation

Main Extension Logic

Here’s the core structure I built:

import {
  reactExtension,
  useCartLineTarget,
  useGraphqlQuery,
  Text
} from '@shopify/ui-extensions-react/checkout';

export const ThankYouBlock = reactExtension(
  'purchase.thank-you.cart-line-item.render-after',
  () => <Extension />
);

function Extension() {
  const [checkoutMessage, setCheckoutMessage] = useState<string | null>(null);
  const { merchandise } = useCartLineTarget();
  
  const { data, errors } = useGraphqlQuery(`
    query GetProductCheckoutMessage($productId: ID!) {
      product(id: $productId) {
        metafield(namespace: "custom", key: "checkout_message") {
          value
        }
      }
    }
  `, {
    variables: { productId: merchandise.product.id }
  });

  useEffect(() => {
    if (!errors && data?.product?.metafield) {
      setCheckoutMessage(data.product.metafield.value);
    }
    if (errors) {
      console.error(errors);
    }
  }, [data, errors]);

  if (!checkoutMessage) return null;

  return (
    <Text emphasis="bold" size="small">
      {checkoutMessage}
    </Text>
  );
}

Multi-Target Configuration

To make this extension work across checkout, thank you, and order status pages, I created three separate exports in the same file:

// Thank you page
export const ThankYouBlock = reactExtension(
  'purchase.thank-you.cart-line-item.render-after',
  () => <Extension />
);

// Order status page  
export const OrderStatusBlock = reactExtension(
  'customer-account.order-status.cart-line-item.render-after',
  () => <Extension />
);

// Checkout page
export const CheckoutBlock = reactExtension(
  'purchase.checkout.cart-line-item.render-after', 
  () => <Extension />
);

Configuration File Updates

Your shopify.extension.toml needs to reference all three targets:

[[extensions.targeting]]
target = "purchase.thank-you.cart-line-item.render-after"
module = "./Checkout.tsx"
export = "ThankYouBlock"

[[extensions.targeting]]
target = "customer-account.order-status.cart-line-item.render-after"
module = "./Checkout.tsx"
export = "OrderStatusBlock"

[[extensions.targeting]]
target = "purchase.checkout.cart-line-item.render-after"
module = "./Checkout.tsx"
export = "CheckoutBlock"

Testing Your Extension

Run your development server:

npm run dev

The extension will render once per product in the cart. If a product doesn’t have the metafield defined, nothing displays (which is exactly what we want).

Important: You can only use Shopify’s approved UI components. Regular HTML elements won’t work - Shopify enforces this to maintain consistency across the checkout experience.

Deployment Process

Deploy the Extension

npm run deploy

Install in Your Store

  1. Choose Custom distribution
  2. Copy your store URL and generate the installation link
  3. Install the app in your store

Configure in Checkout Settings

Navigate to Settings > Checkout > Customize and add your extension to:

  • Information page (checkout)
  • Thank you page
  • Order status page

Real-World Applications

This extension pattern opens up numerous possibilities:

  • Product warnings: “Batteries not included”, “Adult assembly required”
  • Marketing messages: “Limited edition”, “On clearance”
  • Care instructions: “Hand wash only”, “Professional installation recommended”
  • Upsell opportunities: “Perfect with [related product]”
  • Shipping notices: “Ships separately”, “Made to order - 2 week delivery”

Visual Chart: Extension Flow

Customer Journey with Extensions
├── Checkout Page
│   └── Extension renders per cart line item
├── Thank You Page  
│   └── Same extension, same data
└── Order Status Page
    └── Consistent experience maintained

Performance Considerations

Aspect Consideration Impact
API Calls One GraphQL query per cart line item Minimal - queries are cached
Load Time Extensions load after main checkout No impact on checkout performance
Data Size Single line text metafields Negligible bandwidth usage

Common Troubleshooting

Extension handle too long: Shopify limits extension handles to 30 characters. I had to shorten my initial name from “thank-you-order-status-tutorial” to “thank-you-order-status”.

Metafield not displaying: Ensure “Storefront access” is enabled in your metafield settings - this is required for admin API queries.

Extension not appearing: Check that you’ve added the extension to all three pages in your checkout customization settings.

What’s Next?

Now that you understand the basics, consider building more complex extensions:

  • Product recommendations based on cart contents
  • Dynamic shipping information
  • Customer loyalty program integration
  • Review request prompts

The key is starting simple (like this messaging extension) and building complexity as you understand the platform better.

Remember, these extensions render for every product that has the metafield defined, so they’re perfect for product-specific messaging that needs visibility throughout the entire checkout flow.

FAQ

Can I use regular HTML in checkout extensions?
No, you must use Shopify’s approved UI components from the @shopify/ui-extensions-react library to ensure consistency and security.

Do extensions slow down the checkout process?
Extensions load after the main checkout interface, so they don’t impact core checkout performance. GraphQL queries are also cached for efficiency.

Can customers see extensions on all devices?
Yes, Shopify’s UI components automatically adapt to different screen sizes and devices, maintaining a consistent experience.

How many products can display messages simultaneously?
There’s no hard limit - the extension renders once per cart line item that has the required metafield defined.

Can I style the extension appearance?
You can control styling through the component props (size, emphasis, etc.), but you cannot add custom CSS. This maintains design consistency across Shopify’s checkout experience.