--- title: Build pre-auth order status UI extensions description: >- Learn how to build a pre-auth order status UI extension by creating a loyalty app and integrating it into the order status page. source_url: html: >- https://shopify.dev/docs/apps/build/customer-accounts/pre-auth-order-status-page-extensions/build-pre-auth-order-status-page-extensions md: >- https://shopify.dev/docs/apps/build/customer-accounts/pre-auth-order-status-page-extensions/build-pre-auth-order-status-page-extensions.md --- # Build pre-auth order status UI extensions In this tutorial, you'll create two separate customer account UI extensions, with each using different targets to demonstrate the available authentication flows: * An order action menu item that opens a modal and prompts the customer to add a note to their order after logging in. * An extension on the **Order status** page that displays how many loyalty points were earned from the purchase, in a card at the top of the order summary. ![Order Action Menu Target](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/order_action_menu_target-CCiz8g5F.png) ![Order Summary Target](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/order_summary_target-B9Sw6rGY.png) ## What you'll learn In this tutorial, you'll learn how to do the following tasks: * Use the `authenticationState` API to get the authorization context of a customer. * Create an order action menu extension that opens a modal and uses the seamless login method to trigger customer authentication. * Create an extension that's rendered inline on the **Order status** page and uses the `requireLogin` API to trigger customer authentication. ## Requirements [Create a Partner account](https://www.shopify.com/partners) [Create a development store](https://shopify.dev/docs/apps/tools/development-stores) The development store should be pre-populated with [test data](https://shopify.dev/docs/api/development-stores/generated-test-data), including an order associated with the email address you'll use to log in to the customer account experience. [Shopify CLI](https://shopify.dev/docs/apps/tools/cli/installation) You'll need to use the [latest version of Shopify CLI](https://shopify.dev/docs/api/shopify-cli#upgrade). [Scaffold an app](https://shopify.dev/docs/apps/build/scaffold-app) Scaffold an app that uses Shopify CLI. ## Project [View on GitHub](https://github.com/Shopify/customer-account-tutorials/tree/main/preact/example-customer-account--pre-auth--preact) ## Order action menu and seamless login ### Create a customer account UI extension To create a customer account UI extension, you can use Shopify CLI, which generates starter code for building your extension and automates common development tasks. 1. Navigate to your app directory: ## Terminal ```terminal cd ``` 2. Run the following command to create a new customer account UI extension: ## Terminal ```terminal shopify app generate extension --template customer_account_ui --name customer-account-ui-extension ``` You should now have a new extension directory in your app's directory. The extension directory includes the extension script at `src/{FileName}.jsx`. The following is an example directory structure: ## Customer account UI extension file structure ```text └── my-app └── extensions └── my-customer-account-ui-extension ├── src │ └── CustomerAccount.jsx // The index page of the customer account UI extension ├── locales │ ├── en.default.json // The default locale for the customer account UI extension │ └── fr.json // The locale file for non-regional French translations ├── shopify.extension.toml // The config file for the customer account UI extension └── package.json ``` 1) Start your development server to build and preview your app: ## Terminal ```terminal shopify app dev ``` To learn about the processes that are executed when you run `dev`, refer to the [Shopify CLI command reference](https://shopify.dev/docs/api/shopify-cli/app/app-dev). 2) Press `p` to open the developer console. In the developer console page, click on the preview link for your extension. ### Set up the target for your extension Set up the target for your customer account UI extension. [Extension targets](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) control where your extension renders in the customer account flow. This example code uses the following targets: [customer-account.order.action.menu-item.render](https://shopify.dev/docs/api/customer-account-ui-extensions/targets/order-action-menu/customer-account-order-action-menu-item-render)[customer-account.order.action.render](https://shopify.dev/docs/api/customer-account-ui-extensions/targets/order-action-menu/customer-account-order-action-render) In your extension's [`shopify.extension.toml`](https://shopify.dev/docs/apps/build/app-extensions/configure-app-extensions) configuration file, for each of the targets, create an `[[extensions.targeting]]` section with the following information: * **`target`**: An identifier that specifies where you're injecting code into Shopify. * **`module`**: The path to the file that contains the extension code. *** ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "1cf4f1a2-0def-235f-6508-aa91127c34065228f1d0" type = "ui_extension" name = "customer-account-pre-auth-note-preact" handle = "pre-auth-note-preact" [[extensions.targeting]] module = "./src/MenuActionItemButtonExtension.jsx" target = "customer-account.order.action.menu-item.render" [[extensions.targeting]] module = "./src/MenuActionModalExtension.jsx" target = "customer-account.order.action.render" ``` #### Create files for your targets Create files in your extension's `src` directory for each of your targets. In this example, you'll create a file for the order action menu item extension and a file for the order action modal extension. The filenames must match the `module` paths you specified. ### Build the order action menu item and modal #### Render the button Now you'll render the **Add note** order action button. The button isn't being passed a `to` or `onPress` prop. This is how we know to connect this button to the order action modal extension. *** ![Order action menu](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/add_note_button-CEPn39fX.png) ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/src/MenuActionItemButtonExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function MenuActionItemButtonExtension() { return Add note; } ``` #### Build the modal's UI Use `CustomerAccountAction` to extend the target. Here, you'll use `Form`, `TextField`, and `Button` components to add a note to the order. *** Customer account UI extensions are limited to specific UI components exposed by the platform [for security reasons](https://shopify.dev/docs/api/customer-account-ui-extensions#security). You can use checkout UI components and customer account UI components to create a UI that feels seamless within the customer accounts experience, and that inherits a merchant's brand settings. [s-textfield](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/forms/textfield)[s-button](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/actions/button)[s-customer-account-action](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components/actions/customeraccountaction) *** ![modal open](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/modal_open-C0A8u216.png) ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/src/MenuActionModalExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; import {useState} from 'preact/hooks'; export default async () => { render(, document.body); }; function MenuActionModalExtension() { const [note, setNote] = useState(''); function saveNote() { try { // make a request to the server to add a note console.log(note); } catch (error) { console.log(error); } finally { shopify.close(); } } return ( setNote(e.target.value)} rows={3} label="Note for the order" /> Add note shopify.close()} variant="secondary" > Cancel ); } ``` #### Make an API call to store the order note once the customer is logged in The example code uses a comment line to mock the adding note request call. In a production-ready application, make an API call to your server. ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/src/MenuActionModalExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; import {useState} from 'preact/hooks'; export default async () => { render(, document.body); }; function MenuActionModalExtension() { const [note, setNote] = useState(''); function saveNote() { try { // make a request to the server to add a note console.log(note); } catch (error) { console.log(error); } finally { shopify.close(); } } return ( setNote(e.target.value)} rows={3} label="Note for the order" /> Add note shopify.close()} variant="secondary" > Cancel ); } ``` ### Preview the extension Preview your extension to make sure that it works as expected. #### Start your server Run the Shopify CLI `dev` command to build your app and preview it on your development store. 1. In a terminal, navigate to your app directory. 2. Either start or restart your server to build and preview your app: ## Terminal ```bash shopify app dev ``` 3. If prompted, select a development store. 4. Press `p` to open the developer console. 5. In the developer console page, click the preview link for one of your extension targets. The customer accounts experience opens. 1. Ensure that you're logged out. 2. Copy the URL of **Order status** page from a recent order confirmation email, and paste it to the browser directly to be taken to the pre-auth **Order status** page, where your extension will render. 3. Click the **Add Note** button, and you will be redirected to the login page. 4. After you login, you will see the modal opened automatically where you can leave a note. *** ![Order action menu](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/add_note_button-CEPn39fX.png) *** ![modal open](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/modal_open-C0A8u216.png) *** Info To test extensions in pre-authenticated state, the customer shouldn't be logged in. Copy and paste the URL of the **Order status** page from the order confirmation email is the best way to test it. By default, the URL is valid for five uses or two weeks after the order is placed, whichever limit is reached first. If the URL expires, you will need to place a new order to receive a new one. ## Inline extension on the **Order status** page, and `requireLogin` ### Repeat Step 1 to create a new customer account UI extension ### Set up the target for your extension Set up the target for your customer account UI extension. [Extension targets](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) control where your extension renders in the customer account flow. The example code uses `customer-account.order-status.block.render` to render a card in the order summary on the **Order status** page. In your extension's configuration file, for the `customer-account-order-status-block-render` target, create an `[[extensions.targeting]]` section with the following information: **`target`**: An identifier that specifies where you're injecting code into Shopify. **`module`**: The path to the file that contains the extension code. ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "c96aa931-ed42-24ea-b5cf-289deff901edbd465085" type = "ui_extension" name = "customer-account-pre-auth-loyalty-preact" handle = "pre-auth-loyalty-extension-preact" [[extensions.targeting]] module = "./src/BlockLoyaltyExtension.jsx" target = "customer-account.order-status.block.render" ``` #### Create files for your targets Create files in your extension's `src` directory for each of your targets. In this example, you'll create a file for the order status block extension. The filenames must match the `module` paths you specified. ### Order status block extension #### Render loyalty points card Using Polaris web components, add a card to the **Order status** page to let the customer know how many loyalty points they've earned for the order. ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/src/BlockLoyaltyExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockLoyaltyExtension() { async function viewPoints() { await shopify.requireLogin(); } const authenticationState = shopify.authenticationState.value; return ( Points earned from your purchase: { authenticationState === 'pre_authenticated' ? View rewards : 560 } ); } ``` #### Use the `requireLogin` API to direct the customer to login ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/src/BlockLoyaltyExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockLoyaltyExtension() { async function viewPoints() { await shopify.requireLogin(); } const authenticationState = shopify.authenticationState.value; return ( Points earned from your purchase: { authenticationState === 'pre_authenticated' ? View rewards : 560 } ); } ``` #### Determine the authentication state with the `authenticationState` API Using the `authenticationState` API to get the current **Order status** page authentication state. You'll use this later in the tutorial. ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/src/BlockLoyaltyExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockLoyaltyExtension() { async function viewPoints() { await shopify.requireLogin(); } const authenticationState = shopify.authenticationState.value; return ( Points earned from your purchase: { authenticationState === 'pre_authenticated' ? View rewards : 560 } ); } ``` #### Render pre-authenticated state content The extension adds a **View rewards** link to the card. Use the `requireLogin` API to direct the customer to login when the link is clicked. This method routes the customer back to the **Order status** page. The customer will need to re-initiate the action after they're logged in. *** ![Loyalty points in pre-authenticated state](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/loyalty_pre-onheieJy.png) ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/src/BlockLoyaltyExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockLoyaltyExtension() { async function viewPoints() { await shopify.requireLogin(); } const authenticationState = shopify.authenticationState.value; return ( Points earned from your purchase: { authenticationState === 'pre_authenticated' ? View rewards : 560 } ); } ``` #### Render fully authenticated state content In this example, the number of points is hardcoded. *** ![Loyalty points in the fully authenticated state](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/loyalty_fully-BXDEH4JR.png) ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/src/BlockLoyaltyExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockLoyaltyExtension() { async function viewPoints() { await shopify.requireLogin(); } const authenticationState = shopify.authenticationState.value; return ( Points earned from your purchase: { authenticationState === 'pre_authenticated' ? View rewards : 560 } ); } ``` ### Preview the extension Preview your extension to make sure that it works as expected. #### Start your server Run the Shopify CLI `dev` command to build your app and preview it on your development store. 1. In a terminal, navigate to your app directory. 2. Either start or restart your server to build and preview your app: ## Terminal ```bash shopify app dev ``` 3. If prompted, select a development store. 4. Press `p` to open the developer console. 5. In the developer console page, click the preview link for one of your extension targets. The customer accounts experience opens. 1. Place an order, if you haven't already. 2. Click **View your order** from the order confirmation email to access the pre-authenticated **Order status** page. Don't log in. 3. Click the **View rewards** link, and you will be redirected to the login page. 4. After you login, you will be redirected back to the **Order Status** page and see your points balance. *** ![Loyalty points in pre-authenticated state](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/loyalty_pre-onheieJy.png) *** ![Loyalty points in fully authenticated state](https://shopify.dev/assets/assets/apps/customer-accounts/pre-auth-order-status-page-extensions/loyalty_fully-BXDEH4JR.png) *** Info To test extensions in the pre-authenticated state, click **View your order** from the order confirmation email to access the pre-authenticated **Order status** page. Don't log in. By default, the URL only works for 5 times and within 2 weeks. So if the URL is expired, you need to create a new order to get a new URL. ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "1cf4f1a2-0def-235f-6508-aa91127c34065228f1d0" type = "ui_extension" name = "customer-account-pre-auth-note-preact" handle = "pre-auth-note-preact" [[extensions.targeting]] module = "./src/MenuActionItemButtonExtension.jsx" target = "customer-account.order.action.menu-item.render" [[extensions.targeting]] module = "./src/MenuActionModalExtension.jsx" target = "customer-account.order.action.render" ``` ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/src/MenuActionItemButtonExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function MenuActionItemButtonExtension() { return Add note; } ``` ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-note/src/MenuActionModalExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; import {useState} from 'preact/hooks'; export default async () => { render(, document.body); }; function MenuActionModalExtension() { const [note, setNote] = useState(''); function saveNote() { try { // make a request to the server to add a note console.log(note); } catch (error) { console.log(error); } finally { shopify.close(); } } return ( setNote(e.target.value)} rows={3} label="Note for the order" /> Add note shopify.close()} variant="secondary" > Cancel ); } ``` ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "c96aa931-ed42-24ea-b5cf-289deff901edbd465085" type = "ui_extension" name = "customer-account-pre-auth-loyalty-preact" handle = "pre-auth-loyalty-extension-preact" [[extensions.targeting]] module = "./src/BlockLoyaltyExtension.jsx" target = "customer-account.order-status.block.render" ``` ## /preact/example-customer-account--pre-auth--preact/extensions/customer-account-pre-auth-loyalty/src/BlockLoyaltyExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockLoyaltyExtension() { async function viewPoints() { await shopify.requireLogin(); } const authenticationState = shopify.authenticationState.value; return ( Points earned from your purchase: { authenticationState === 'pre_authenticated' ? View rewards : 560 } ); } ``` ## Tutorial complete! Nice work - what you just built could be used by Shopify merchants around the world! Keep the momentum going with these related tutorials and resources. ### Next Steps [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/apps/customer-accounts/best-practices/deciding-extension-placement) [Extension placement](https://shopify.dev/docs/apps/customer-accounts/best-practices/deciding-extension-placement) [Explore extension placement options and make informed decisions on where to position them.](https://shopify.dev/docs/apps/customer-accounts/best-practices/deciding-extension-placement) [![](https://shopify.dev/images/icons/32/globe.png)![](https://shopify.dev/images/icons/32/globe-dark.png)](https://shopify.dev/docs/apps/customer-accounts/best-practices/localizing-ui-extensions) [Localize your extension](https://shopify.dev/docs/apps/customer-accounts/best-practices/localizing-ui-extensions) [Learn about localizing your customer account UI extensions for international merchants and customers.](https://shopify.dev/docs/apps/customer-accounts/best-practices/localizing-ui-extensions) [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) [Extension targets](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) [Learn about the extension targets offered for customer accounts.](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) [![](https://shopify.dev/images/icons/32/heart.png)![](https://shopify.dev/images/icons/32/heart-dark.png)](https://shopify.dev/docs/apps/customer-accounts/best-practices/ux-guidelines) [UX guidelines](https://shopify.dev/docs/apps/customer-accounts/best-practices/ux-guidelines) [Follow our UX guidelines for customer accounts to ensure a consistent and satisfying user experience.](https://shopify.dev/docs/apps/customer-accounts/best-practices/ux-guidelines) [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components) [Polaris web components](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components) [Learn about the components you can use to build customer account UI extensions.](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components) [![](https://shopify.dev/images/icons/32/key.png)![](https://shopify.dev/images/icons/32/key-dark.png)](https://shopify.dev/docs/apps/customer-accounts/order-status-page#authentication-states) [Order status page authentication states](https://shopify.dev/docs/apps/customer-accounts/order-status-page#authentication-states) [Learn about the difference between each authentication state on the **Order status** page.](https://shopify.dev/docs/apps/customer-accounts/order-status-page#authentication-states)