Build a discounts UI with Admin UI extensions
With Shopify Functions, you can create new types of discounts that apply to cart lines, order subtotals, shipping rates, or any combination of these.
Additionally, you can use Admin UI extensions to create a UI, displayed on the discount details page of Shopify admin, for merchants to configure your app's Discount Function. To do this, this custom UI will use metafields to communicate with your Discount Function.
This tutorial describes how to create an Admin UI Extension that merchants can use to configure a Discount Function.

Anchor to What you'll learnWhat you'll learn
In this tutorial, you'll learn how to do the following tasks:
- Create an Admin UI Extension, written in React and hosted by Shopify
- Build a Discount Function that applies a percentage off cart lines, order subtotal and shipping rates
- Associate your Admin UI extension to your Discount Function, so merchants can use the UI to configure the discounts provided by the Discount Function
- Configure app-scoped metafields to store discount settings
After completing this tutorial, you'll be able to use your Shopify admin to configure a Discount Function that discounts cart lines (filtered by collection), order subtotal, and shipping.
Requirements
For example, follow the Build a Discount Function tutorial, or build your own app and Discount Function using the Discount API.
Project
Anchor to Create an Admin UI ExtensionCreate an Admin UI Extension
First, scaffold the Admin UI extension that will provide the UI that merchants can use to configure your Discount Function.
- Navigate to your app's directory:
Terminal
- Run the following command to create a new Discount Function Settings Admin UI Extension:
Terminal
Anchor to Configure your Admin UI ExtensionConfigure your Admin UI Extension
Your Admin UI extension will use a metafield to tell your Discount Function which collections of products to discount, and the specific discount percentage to offer for products, order subtotal, and shipping. The Discount Function will use this metafield to dynamically create discount operations.

Anchor to MetadataMetadata
Specify your extension's metadata in the [[extensions]]
section of its associated configuration file. In this case, name
and description
will appear in the Discounts and discount details page of the Shopify admin.
Shopify provides localization tools, and you can use them to localize the name and description of Discount Functions. To learn more, refer to localizing your Shopify app.
Anchor to TargetTarget
In the [[extensions.targeting]]
section of your extension's configuration file, you'll define its target
and module
.
target
specifies where in the Shopify Admin surface the extension should display. For this tutorial, set target
to admin.discount-details.function-settings.render
.
module
specifies a path to the file that contains the main export.
Refer to App Extensions Common properties
for more information.
Anchor to Associate your Discount Function with the Admin UI ExtensionAssociate your Discount Function with the Admin UI Extension
Your Admin UI extension can configure your Discount Function. To connect them, open your Function's .toml
configuration file and find the [extensions.ui]
section. Set the handle property to match the handle in your Admin UI extension's shopify.extension.toml
file.
Anchor to Review the Admin UI ExtensionReview the Admin UI Extension
Before continuing on with the tutorial, review the code for your Admin UI extension, so that you understand how it's configured, how it displays data, and how it manages state.
Anchor to Initialize the Admin UI ExtensionInitialize the Admin UI Extension
The discount details page renders the admin.discount-details.function-settings.render
target. The target
must be provided to the reactExtension
function, and must match the extensions.targeting.target
defined in the previous step.
Anchor to Use UI componentsUse UI components
Admin UI extensions are rendered using Remote UI, which is a fast and secure remote-rendering framework. Because Shopify renders the UI remotely, components used in the extensions must comply with a contract in the Shopify host. Shopify provides these components through the Admin UI extensions library.
Anchor to The ,[object Object], componentThe App
component
App
componentThe App
component is the main component of the extension. It renders a form with percentage fields and a collection picker. It uses the useExtensionData
hook to manage the state of the form.
Anchor to The ,[object Object], and ,[object Object], componentsThe AppliesToCollections
and CollectionsSection
components
AppliesToCollections
and CollectionsSection
componentsThe AppliesToCollections
component renders a Select
component which allows users to dynamically select Collections
from your shop. To do this, it uses the Admin UI Extensions resource picker API.
The CollectionsSection
component renders the collections section, displaying the selected collections and a button to add or remove collections.
Anchor to Manage the form's dirty stateManage the form's dirty state
Since the ResourcePicker
doesn't directly update the form's state, it doesn't enable the Save action on the discount details page.
To fix this, add a hidden TextField
, inside a Box
component, and use it to store the selected collection IDs as a serialized value. This hidden field integrates with the FunctionSettings
component, enabling the form to detect changes and allowing merchants to save their discount settings.
Anchor to Manage state with the ,[object Object], hookManage state with the useExtensionData
hook
useExtensionData
hookThe useExtensionData
hook manages the state of the form. It uses the useApi
hook to interact with the GraphQL Admin API. The useEffect
hook is used to set the initial state of the form.
Anchor to Metafields in Admin UI ExtensionsMetafields in Admin UI Extensions
Metafields are used to persist shared state between the Discount Function and the Admin UI Extension. Metafields are scoped to an app, and they're unique for each discount created.
Anchor to Review how the code creates metafieldsReview how the code creates metafields
For security reasons, you must create your metafield definition under a reserved namespace. Reserved metafield definitions keep your app's metafields private, and you have to set any additional permissions manually. Because this Admin UI extension runs in Shopify admin, you'll need to request these permissions when installing the app.
Use the $app
scope to create a metafield definition under a reserved namespace. The namespace and key must be unique.
Learn more about metafield definitions under an app-scoped namespace.
Anchor to Review the code that updates metafieldsReview the code that updates metafields
When a merchant uses your Admin UI extension to update a discount's details, the applyExtensionMetafieldChange
function saves the updated form values directly into the discount's metafield in Shopify.
Anchor to Apply cart line and order subtotal discountsApply cart line and order subtotal discounts
Discount Functions return operations which contain discount candidates, that are responsible for applying discounts to cart lines, order subtotals, and shipping rates.
Anchor to Update the Discount Function configuration to use Metafields in input queriesUpdate the Discount Function configuration to use Metafields in input queries
Admin UI extensions can use metafields to share data with Discount Functions.
To allow your Discount Function to receive these metafield values as input variables, update your Function's shopify.extension.toml
configuration file. Under [extensions.input.variables]
, set namepace
and key
to the same values set in your Admin UI extension code.
Anchor to Use Metafield properties as input variablesUse Metafield properties as input variables
In the previous step, you defined an input variable that uses a discount Metafield. This metafield is queried and updated by the UI Extension.
The input GraphQL query can specify reference fields found in the object stored by a metafield. For example, collectionIds
is a key present in the metafield created by the Admin UI extension created above. This is particularly useful when using fields with arguments such as the inAnyCollection
field.
Anchor to Use input variables to query ,[object Object], fieldUse input variables to query inAnyCollection
field
inAnyCollection
fieldThe inAnyCollection field on the product
field allows your Discount Function to dynamically determine whether a given product
in the cart belongs to any of many collections.
Anchor to Query the metafield definition to get the discount percentagesQuery the metafield definition to get the discount percentages
The namespace
and key
must be the same as the namespace
and key
used in the Admin UI Extension, since that metafield stores the discount percentages configured by the extension.
Anchor to Update the Discount Function to parse the metafieldUpdate the Discount Function to parse the metafield
Parse the metafield which is stored on the discount
field to get the function configuration for the cart.lines.discounts.generate.run
target.
Anchor to Apply cart line and order subtotal discountsApply cart line and order subtotal discounts
Add the cart line and order subtotal operations, using the percentage values set in the discount metafield configuration.
Anchor to Discount cart lines based on collection membershipDiscount cart lines based on collection membership
Conditionally add targets to the candidates using the line.merchandise.product.inAnyCollection
from the input query.
Anchor to Use metafields in Discount Function delivery options targetUse metafields in Discount Function delivery options target
The Delivery Options target is used to apply discounts to shipping rates.
Anchor to Query the metafield definitionQuery the metafield definition
The namespace
and key
must be the same as the namespace
and key
used in the Admin UI Extension.
This metafield definition is used to obtain the defined percentage for shipping rate discounts.
Anchor to Update the Discount Function to parse the metafieldUpdate the Discount Function to parse the metafield
Parse the metafield on the discount
field to get the percentage value to reduce the delivery groups shipping rates.
Anchor to Apply discounts to delivery groupsApply discounts to delivery groups
Add the delivery groups operations using the percentage values from the discount metafield configuration.
Anchor to Request the access scopes for reading collectionsRequest the access scopes for reading collections
To access collections, your app must have the read_products
app scope. To set this up, add the read_products
scope to your shopify.app.toml
file.
Anchor to Deploy your app with new access scopesDeploy your app with new access scopes
-
Deploy your updated configuration to Shopify:
Terminal
shopify app deploy -
Restart your app development server:
Terminal
shopify app dev -
Open or reinstall your app using the URL provided by Shopify CLI. To preview your extensions, press
p
in the terminal window where you started your app. -
Accept the new access scope permissions in your store.
Anchor to Test your Discount FunctionTest your Discount Function
Anchor to Create a discount using your appCreate a discount using your app
- In the extension preview console opened in the previous step, click on the preview link for the
admin-discount-details.function-settings.render
extension target. This opens the discount details page. - Your Admin UI Extension should appear on this page.
- Configure your discount, and click Save.
You should see a new discount in the discounts list.

Anchor to Deactivate other discountsDeactivate other discounts
To ensure that the newly created discount is the only active discount, deactivate or delete all other discounts.
Anchor to Build a cartBuild a cart
Open your development store and build a cart with a single item in it, use a product that belongs to the collection you configured in the Admin UI Extension.
Anchor to Validate discount applicationValidate discount application
On the cart page, you should see that your Discount Function has applied a discount to a cart line and the order subtotal. When you navigate to the checkout page and provide a shipping address, you'll see the shipping discount.
Anchor to Review the Function executionReview the Function execution
-
In the terminal where
shopify app dev
is running, review your Function executions.When testing Functions on development stores, the
dev
output shows Function executions, debug logs you've added, and a link to a local file containing full execution details. -
In a new terminal window, use the Shopify CLI command
app function replay
to replay a Function execution locally. This lets you debug your Function without triggering it again on Shopify.Terminal
shopify app function replay -
Select the Function execution from the top of the list. Press
q
to quit when you are finished debugging.