Shopify Checkout UI Extensions

RMAG news

Shopify is a leading e-commerce platform that empowers businesses of all sizes to seamlessly create, manage, and scale their online stores, offering robust tools and integrations that cater to a wide array of needs.
This article explains how we at Yeti recently created a custom Shopify App using Checkout UI extensions to pull real-time data from a client’s Enterprise Resource Planning (ERP) system into Shopify. By the end of this article you will better understand what Shopify Checkout UI extensions are, how to approach building them, and some of the things to keep in mind during the implementation process.

What are Shopify Checkout UI Extensions?

Checkout UI extensions are customizable components available to users with Shopify Plus stores. They are essentially small React applications that use Shopify-provided tools and APIs to securely and reliably extend existing Shopify features. The extensions run in isolated sandbox environments with limited access to browser APIs, helping to protect customer data and ensure the checkout process remains secure.

Why Did We Need One?

Our client, a construction materials and equipment sourcing company, needed a direct connection between their ERP system and Shopify checkout page to display an up-to-date list of active projects to their customers during checkout. This feature would help our client’s customers indicate which project their order is for, simplifying order fulfillment.

How Did We Build It?

First, to build a Shopify Checkout UI extension you will need access to a Shopify Plus store. Checkout UI extensions are currently only available to merchants on a Shopify Plus plan.

You’ll also need to install Shopify’s command-line interface, have a Partner account, and have access to development store for testing the extension.

Identify the Extension Target

Extensions can be added to any of the extension targets defined by Shopify. The target defines where in the storefront our extension will appear. For example, if we wanted to add an extension just below the checkout page’s header we might choose a target of purchase.checkout.header.render-after.

We chose an appropriate target within the Shopify checkout flow to add our extension, making sure it fits naturally without disrupting the user experience.

Create a Shopify App

We created our new app locally using the Shopify CLI. This generates all the code needed for developing a Shopify App.

Our extension needed network access since it requests data from our client’s ERP at runtime. It also needed checkout-blocking permissions to prevent customers from submitting orders without selecting a project id. We configured both of these permissions with the following block in our extension’s shopify.extension.toml:

[extensions.capabilities]
# Gives your extension access to make external network calls, using the
# JavaScript `fetch()` API. Learn more:
# https://shopify.dev/docs/api/checkout-ui-extensions/unstable/configuration#network-access
network_access = true

# Allows extension to block progress of the checkout flow.
block_progress = true

This file is also where other general configuration for the app is located, including the extension target we chose above.

We also had to request network access for our app in the Shopify Partners dashboard, which is not granted by default. At the time of writing, once the request is submitted it is automatically approved and the app is immediately granted network access permissions.

Now for the checkout UI extension itself — which, as a reminder, is a small React app created by the Shopify CLI that will be added to our store at the target we selected above — we had several requirements:

Request up-to-date data from our client’s ERP system via our backend.
Prove to our backend that the request came from our Shopify extension.
Display a list of active projects to customers on the checkout page.
Prevent customers from checking out if they haven’t selected an active project from the list.
Store the selected active project identifier on the Shopify order so that our client can efficiently fulfill the order.

I’ll cover the first two points when describing our extension’s backend below.

Once we have the project data we need, showing a list of projects took some basic React code:

<Banner title=”Select Project for Order”>
{!projects.length ? (
<>Loading…</>
) : (
<Select
label=”Active Projects”
options={projects.map((project) => ({
value: project.projectId,
label: `${project.projectId} – ${project.description}`,
}))}
onChange={handleChange}
value={selectedProject}
/>
)}
</Banner>

All we needed to do here was to first show a loading value while we wait for the data from our backend, and then to show a dropdown with the list of active projects that was returned.

This is pretty standard React code, which is one of the great things about working with the Shopify extension system: if you already know React it’s pretty easy to get started.

To prevent customers from checking out before selecting a project, we used a React hook provided by Shopify called useBuyerJourneyIntercept. This hook allows us to tweak what happens when any number of conditions are met, giving us more control over the checkout flow.

We used this hook to set up the progress blocking behavior we added permissions for previously in our extension’s configuration file:

useBuyerJourneyIntercept(({ canBlockProgress }) => {
return canBlockProgress && !selectedProject
? {
behavior: “block”,
reason: “No Project Selected”,
errors: [
{
// shows an error at the page level
message:
“Please select a project before proceeding with your order.”,
},
],
}
: {
behavior: “allow”,
};
});

This checks both whether this extension has permission to block progress and whether the user has selected a project. If both are true we allow the customer to submit their order, otherwise we block progress and show an appropriate error message.

Finally, to store the customer’s selected project on the Shopify order we used another React hook provided by Shopify called useApplyMetafieldsChange. This hook provided a function that allowed us to write custom values to meta fields on the Shopify order.

We used this function in the change handler of our dropdown component to store the selected project id:

const handleChange = (projectId: string) => {
setSelectedProject(projectId);

applyMetafieldsChange({
type: “updateMetafield”,
namespace: “<client name>”,
key: “projectId”,
valueType: “string”,
value: value,
});
};

Develop the Backend

The final piece of the puzzle was a custom backend that bridges between our Shopify App and the ERP system. We couldn’t request data directly from our Shopify App since all the app’s code is sent to the browser, so any sensitive credentials would be essentially public. Our backend’s responsibilities are first to validate that all incoming requests came from Shopify, and then to return the list of active projects to our app.

We can validate that incoming requests came from Shopify by verifying that the session token sent on the request from our app is valid. Once we verify that the request came from Shopify, we can request the data that we need from our client’s ERP system and return it to our app in an easy-to-use format. With this piece in place we are finally able to pull the list of active projects into our Shopify store’s checkout page.

In closing, our work to create a custom Shopify Checkout UI extension has streamlined our client’s checkout process, linking it directly with their ERP system for real-time project data.

This project not only solved a complex technical challenge for our client but also demonstrated the robust customization capabilities of Shopify Plus. We hope this overview of the development process has given you a clearer understanding of what Shopify Checkout UI extensions can do and how they can be effectively implemented.

Yeti is an IoT application development company. If you’d like to learn more about what we do, be sure to take a look at our extensive library of IoT software development content.

Leave a Reply

Your email address will not be published. Required fields are marked *