Build a pre-purchase Shopify checkout UI extension
Expected time: 25 minutes
Checkout UI extensions are an important part of the Shopify developer ecosystem. Since Shopify announced the deprecation of checkout.liquid, it has become more important than ever for developers to be able to swiftly migrate existing Plus-merchant checkout functionality over to checkout UI extensions.
In this tutorial, you will build a pre-purchase upsell extension that allows merchants to select multiple products in an embedded admin app that can be offered to buyers during checkout. If more than one product is selected, the OpenAI connection and vector embeddings will be used to examine the cart contents and recommend a product to the buyer.
Step 1: Create a Gadget app and connect to Shopify
Your first step will be to set up a Gadget project and connect to a Shopify store via the Shopify connection. Create a new Gadget application at gadget.new and select the Shopify app template.
Because you are adding an embedded frontend, you are going to connect to Shopify using the Partners connection.
Now we will set up a custom Shopify application in the Partners dashboard.
Both the Shopify store Admin and the Shopify Partner Dashboard have an Apps section. Ensure that you are on the Shopify Partner
Dashboard before continuing.
Click the Create App button
Click the Create app manually button and enter a name for your Shopify app
Click on Settings in the side nav bar
Click on Plugins in the modal that opens
Select Shopify from the list of plugins and connections
Copy the Client ID and Client secret from your newly created Shopify app and paste the values into the Gadget Connections page
Click Connect on the Gadget Connections page to move to scope and model selection
Now we get to select what Shopify scopes we give our application access to, while also picking what Shopify data models we want to import into our Gadget app.
Select the scopes and models listed below and click Confirm to connect to the custom Shopify app
Enable the read scope for the Shopify Products API, and select the underlying Product, Product variant, and Product media models that we want to import into Gadget
Now we want to connect our Gadget app to our custom app in the Partner dashboard.
In your Shopify app in the Partner dashboard, click on Configuration in the side nav bar so you can edit the App URL
and Allowed redirection URL(s) fields
Copy the App URL and Allowed redirection URL from the Gadget Connections page and paste them into
your custom Shopify App
Now we need to install our Shopify app on a store.
Click on the store we want to use to develop our app
You may be prompted about Store transfer being disabled. This is okay, click Install anyway
Click Install app to install your Gadget app on your Shopify store
Having an issue installing?
If you are getting a permissions denied error when installing your app, try logging in to the Shopify store Admin!
You will be redirected to an embedded admin app that has been generated for you. The code for this app template can be found in web/routes/index.jsx.
Do not sync your data models yet! You will want to run product descriptions through OpenAI's embeddings API so they can be offered to
buyers in the checkout.
Now that your app is connected to Shopify, the next step will be to start modifying your app backend and database to support vector embeddings.
Step 2: Add custom fields to the shopifyProduct model
You will use vector embeddings to recommend a product to buyers based on the contents of their cart. To do this, you need to add a new field to the shopifyProduct model that will store the vector embeddings for each product.
You can also add a field to keep track of the number of times a product was offered to buyers in the checkout.
Count the number of times a product has been offered.
Step 3: Add the OpenAI connection
You need to set up the OpenAI connection in Gadget to generate vector embeddings. The OpenAI connection gives you an authenticated API client used to call the OpenAI API.
Navigate to Settings → Plugins → OpenAI
Click Add connection with Gadget development keys selected
Gadget gives you OpenAI credits to help you start building without requiring you to enter an OpenAI API key. If you have used your
credits, you will need to enter your OpenAI API key.
Step 4: Add action to generate embeddings
Now that you have finished data modeling and setting up the OpenAI connection, you can start customizing your backend.
First, we need an action we can call to generate the vector embedding for offered products.
Add a new generateEmbedding.js action file at api/models/shopifyProduct/actions
calls the embeddings.create API to generate a vector embedding for the product title and description
uses the internal API to save the embedding with api.internal.shopifyProduct.update()
Now you need to call this action when a product's create (or update) action is run.
Calling createEmbedding when a product record is created
You want to reliably generate embeddings for each product so they can all be offered as part of the pre-purchase upsell. Because you want this reliability, you can use Gadget's built-in background actions system to enqueue calls to generateEmbedding actions.
Background actions have built-in concurrency control and retry handling, making it easier to ensure that each product gets a generated embedding.
Paste the following code snippet in api/models/shopifyProduct/actions/create.js:
You can also use the code in the onSuccess function in api/model/shopifyShop/update.js so embeddings are
re-generated when the product description changes.
You can create a new file, export a function from that file, and import that shared function in both your create and update actions.
Step 5: Sync your Shopify data
Now that embeddings will be generated when your shopifyProduct.create action is called, you can sync data from Shopify. This data sync will call the create action for each product, which enqueues the generateEmbedding action.
A data sync will sync all existing products for your installed Shopify store. If you have a lot of products, this may take a while and use
your OpenAI credits. This will work for large collections of products, but you may want to test with less products for this tutorial.
Navigate to Settings → Plugins → Shopify → Installs
Click Sync to start a data sync
You will see your Queues count change in the Gadget editor as generateEmbedding actions are enqueued and then executed.
If you navigate to api/models/shopifyProduct/data, you should see that the embedding field has data.
Step 6: Add an action to fetch offers
The last step before building the extension is creating an action that can be called that will recommend a product to buyers based on the contents of their cart.
This action will be called from the checkout extension.
Add a global action to your app at api/actions/recommendProduct.js and add the following code:
11// generate an embedding for the contents of the current cart
12let cartContents =
13"This is a list of product titles and descriptions in a shopping cart. I want to find a product that can be recommended based on the similarity to these products: ";
11// generate an embedding for the contents of the current cart
12let cartContents =
13"This is a list of product titles and descriptions in a shopping cart. I want to find a product that can be recommended based on the similarity to these products: ";
generates an embedding based on the titles and descriptions of the products in a buyer's cart
finds a recommended product using api.shopifyProduct.findFirst, which uses cosine similarity sorting with the generated cart embedding to find the product that most closely matches the current products in the cart
Step 7: Update action permissions
Authorization is built into Gadget, which means that you need to give buyers access to your app's API.
Roles are already created for both merchants and buyers. Buyers in the checkout will be granted the unauthenticated role.
Navigate to accessControl/permissions in the Gadget editor
Grant the unauthenticated role access to the recommendProduct action
Now that buyers in the checkout have permission to call your action, you can build your extension.
Step 8: Add embedded frontend to track what was offered
You can also modify the admin-embedded frontend to display the count of what products are offered to buyers.
Select the same Partner app and development store you used to connect to Shopify when prompted by Shopify's CLI
Select JavaScript React when prompted for the extension language
This command will generate an extensions folder at your project root, and your extension will be generated by Shopify.
Install the @gadgetinc/shopify-extensions package
You can install the @gadgetinc/shopify-extensions package that contains tooling to make it easier to work with your client inside extensions.
cd into the extensions/ai-pre-purchase-ext folder of your app
Run the following in your terminal:
install the required packages
yarnadd @gadgetinc/shopify-extensions
cd back to your project root
Modify the extension toml configuration file
The first thing you need to do is modify your extension's shopify.extension.toml file. You need to define your metafield as input and allow access to the Storefront API.
Turn on network access in your extensions/ai-pre-purchase-ext/shopify.extension.toml:
displays a loading widget until the offer is fetched from Gadget
checks to see if the offer is already in the cart or there is an error with the fetch
displays the offer to buyers
adds the offered product to the cart at the press of a button
Test your extension
Now that you've built your extension, you need to test it out in a checkout.
Start the extension dev server by running shopify app dev from your app root
When prompted, make sure you select the same development store you used to connect your Gadget app to Shopify
Open the Preview URL to access the Shopify Developer Console and open the provided Checkout UI extension URL
You should be able to see the extension in the checkout UI.
See the offer in your admin embedded UI
You can go back to your Shopify store admin and see that the count in your table has increased. If you refresh your Shopify checkout tab, the table will update in real time.
Congrats! You have successfully built a custom pre-purchase checkout extension with Gadget!
Next steps
Have questions about the tutorial? Join Gadget's developer Discord to ask Gadget employees and join the Gadget developer community!
Extend this tutorial
If you want to extend this tutorial, you could:
build an embedded frontend for merchants to select what products can be offered in the checkout
build an embedded frontend that serves as an analytics dashboard and lets merchants know what products have been added to a buyer's cart and purchased
Other
Want to learn more about data modeling and writing custom code effects in Gadget? Try out the product tagger tutorial: