Close

Sign up to Gadget

Build a product recommendation chatbot for a Shopify store using OpenAI and Gadget

-

About

Learn how to use OpenAI and Shopify theme extensions to build a storefront chatbot that uses OpenAI to recommend products to shoppers.

Problem

Solution

Result

Build a product recommendation chatbot for a Shopify store using OpenAI and Gadget

Riley Draward
May 12, 2023

Topics covered: Shopify connections, AI + vector embeddings, HTTP routes
Time to build: ~30 minutes

Large Language Model (LLM) APIs allow developers to build apps that can understand and generate text. We can use OpenAI's APIs to build a chatbot that can understand a shopper's question and respond with product recommendations.

In this tutorial, you will learn how to:

Requirements
To get the most out of this tutorial, you will need:
 - A Shopify Partners account
 - A development store

You can fork this Gadget project and try it out yourself. You will still need to set up the Shopify Connection and theme app extension after forking. Read on to learn how to connect Gadget to a Shopify store!

Fork on Gadget

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.

A screenshot of the Shopify app template tile selected on the new app modal, with a domain entered

Our first step is going to be setting 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 on Apps link in Shopify Partners Dashboard
  • Click the Create App button
Click on Create app button
  • Click the Create app manually button and enter a name for your Shopify app
Shopify's app creation landing page in the Partners Dashboard
  • Go to Connections in Settings underneath the Plugins page in your Gadget app
The Gadget homescreen, with the Connections link highlighted
  • Copy the Client ID and Client secret from your newly created Shopify app and paste the values into the Gadget Connections page
Screenshot of the Partners card selected on the 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.

  • Enable the Products Read API scope, and select the underlying Product and Product Image models that we want to import into Gadget
Select Product API scope + model
  • Click Confirm

Now we want to connect our Gadget app to our custom app in the Partners dashboard.

  • In your Shopify app in the Partners dashboard, click on App setup 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
Screenshot of the connected app, with the App URL and Allowed redirection URL(s) fields

Now you can install your app on a store from the Partners dashboard. Do not sync data yet! You're going to add some code to generate vector embeddings for your products before the sync is run.

Step 2: Set up OpenAI connection

Now that you are connected to Shopify, you can also set up the OpenAI connection that will be used to fetch embeddings for product descriptions. Gadget provides OpenAI credits for testing while building your app, so you don't need a personal OpenAI API key to get started.

  1. Click on Settings in the nav bar
  2. Click on Plugins
  3. Click on the OpenAI connection
  4. Select the Use Gadget's API keys option in the modal that appears OR enter your own OpenAI API key

Your OpenAI connection is now ready to be used!

Step 3: Add data models for chat responses

Now we need a new data model to capture the chat responses from OpenAI, and the products recommended to shoppers. We need to use a <inline-code>has many through<inline-code> relationship to relate the chat response to the recommended products.

ERD of the chatbot data models, showing the has many through relationship between chatLog and shopifyProduct, through recommendedProduct. The diagram also shows that shopifyProduct has many shopifyProductImage
  1. Click + next to DATA MODELS to add a new model
  2. Name the model <inline-code>chatLog<inline-code>
  3. Click + next to FIELDS to add a new field
  4. Name the field <inline-code>response<inline-code> and leave it as a string field

This string field will record the response coming back from OpenAI. We also want to keep track of the products that were recommended, so we need to add a has many through relationship to the <inline-code>shopifyProduct<inline-code> model.

  1. Add another field to <inline-code>chatLog<inline-code> called <inline-code>recommendedProducts<inline-code>
  2. Set the field type to a <inline-code>has many through<inline-code> relationship
  3. Set the sibling to <inline-code>shopifyProduct<inline-code> and the <inline-code>joinModel<inline-code> to <inline-code>recommendedProduct<inline-code>, this will create a new <inline-code>recommendedProduct<inline-code> model
  4. Name the field in <inline-code>recommendedProduct<inline-code> that relates to the <inline-code>chatLog<inline-code> model, <inline-code>chatLog<inline-code>
  5. Name the field in <inline-code>recommendedProduct<inline-code> that relates to the <inline-code>shopifyProduct<inline-code> model, <inline-code>product<inline-code>
  6. Name the field in the <inline-code>shopifyProduct<inline-code> model that relates to the <inline-code>recommendedProduct<inline-code> model, <inline-code>chatRecommendations<inline-code>
A screenshot of the has many through relationship defined between the chatlog and shopifyProduct models

Step 4: Add <inline-code>vector<inline-code> field to <inline-code>shopifyProduct<inline-code> model

Before you add code to create the embeddings from product descriptions, you need a place to store the generated embeddings. You can add a vector field to the <inline-code>shopifyProduct<inline-code> model to store the embeddings.

The vector field types store a vector, or array, of floats. It is useful for storing embeddings and will allow you to perform vector operations like cosine similarity, which helps you find the most similar products to a given chat message.

Learn more about OpenAI, LLMs, and vector embeddings

You are going to use Gadget's built-in OpenAI connection to generate vector embeddings for product descriptions. These embeddings will be used to perform a semantic search to find the products that best match a shopper's chat message.

LLMs and vector embeddings are relatively new technologies, and there are many resources available to learn more about them. Here are some resources to get you started:
 - Building AI apps in Gadget
 - Sorting by vector fields Gadget API docs
  - OpenAI docs

To add a vector field to the <inline-code>shopifyProduct<inline-code> model:

  1. Go to the <inline-code>shopifyProduct<inline-code> model in the navigation bar
  2. Click on + in the FIELDS section to add a new field
  3. Name the field <inline-code>descriptionEmbedding<inline-code>
  4. Set the field type to <inline-code>vector<inline-code>
A screenshot of the Description Embedding vector field defined on the Shopify Product model

Now you are set up to store embeddings for products! The next step is adding code to generate these embeddings.

Step 5: Write code effect to create vector embedding

Now you can add some code to create vector embeddings for all products in your store. You will want to run this code when Shopify fires a <inline-code>products/create<inline-code> or <inline-code>products/update<inline-code> webhook. To do this, you will create a code effect that runs when a <inline-code>shopifyProduct<inline-code> is created or updated.

  1. In the FILES explorer, hover over the <inline-code>shopifyProduct<inline-code> folder and click on + to create a new file
  2. Name the file <inline-code>createEmbedding.js<inline-code>
  3. Paste the following code into <inline-code>shopifyProduct/createEmbedding.js:<inline-code>

In this snippet:

  • the OpenAI connection is accessed through connections.openai and the embeddings.create() API is called
  • the internal API is used in the <inline-code>onSuccess<inline-code> function to update the <inline-code>shopifyProduct<inline-code> model and set the <inline-code>descriptionEmbedding<inline-code> field

The internal API needs to be used because the <inline-code>shopifyProduct<inline-code> model does not have a Gadget API trigger on this action by default. You can read more about the internal API in the Gadget docs.

Now call this function from your <inline-code>shopifyProduct/actions/create.js<inline-code> and <inline-code>shopifyProduct/actions/update.js<inline-code> actions:

  1. Open <inline-code>shopifyProduct/actions/create.js<inline-code> and paste the following code:

  1. Open <inline-code>shopifyProduct/actions/update.js<inline-code> and paste the following code:

Now vector embeddings will be generated when a new product is created, or an existing product is updated.

Generate embeddings for existing products

Now that the code is in place to generate vector embeddings for products, you can sync existing Shopify products into your Gadget app's database. To do this:

  1. Click on Settings in the nav bar
  2. Click on the Plugins page
  3. Select the Shopify connection
  4. Click on Shop Installs for the connected Development app
Screenshot of the connected app on the Shopify connections page, with the Shop Installs button highlighted
  1. Click on the Sync button for the store you want to sync products from
Screenshot of the shop installs page, with an arrow added to the screenshot to highlight the Sync button for the connected store

Product and product image data will be synced from Shopify to your Gadget app's database. The code effect you added will run for each product and generate a vector embedding for the product. You can see these vector embeddings by going to the Data page for the shopifyProduct model. The vector embeddings will be stored in the descriptionEmbedding field.

A screenshot of the Data page for the shopifyProduct model. The descriptionEmbedding column is highlighted, with vector data generated for products.

Running into rate limit errors?

If you are running into rate limit errors when generating embeddings while syncing, try using your own OpenAI API key. You can add your own API key to the OpenAI connection by clicking on the Settings tab in the OpenAI connection and selecting the Use my own API key option.

Step 6: Add <inline-code>/chat<inline-code> HTTP route

We will use an HTTP route to handle incoming chat messages from the storefront. The route will take a message from the shopper, use cosine similarity to determine what products to recommend, and stream a response from OpenAI back to the client.

  1. Hover over the routes folder in the FILES explorer and click on + to create a new file
  2. Name the file POST-chat.js

Your app now has a new HTTP route that will be triggered when a POST request is made to <inline-code>/chat<inline-code>. You can add code to this file to handle incoming chat messages.

  1. Paste the following code in <inline-code>routes/POST-chat.js<inline-code>:

This code will:

  • create a vector embedding from the shopper's message using the OpenAI connection using <inline-code>connections.openai.embeddings.create()<inline-code>
  • use cosine similarity to find the 2 most similar products to the shopper's message using the Gadget API:

use the OpenAI chat API to generate a response

  • use the OpenAI chat API to generate a response using the <inline-code>gpt-4-1106-preview<inline-code> model

  • stream the response back to the client and save the records to the database using <inline-code>reply.send(openAIResponseStream(chatResponse, { onComplete }))<inline-code>
  • <inline-code>onComplete<inline-code> is a callback function that is called after the stream is finished

Set up CORS handling

Before we can call our /chat route from a theme extension, we need to enable CORS handling. To do this we will use the <inline-code>@fastify/cors<inline-code> plugin.

  1. Open the Gadget command palette using P or Ctrl P
  2. Enter <inline-code>><inline-code> in the palette to change to command-mode
  3. Run the following command to install the <inline-code>@fastify/cors<inline-code> plugin:

Once the plugin is installed, you can add it to your app's configuration:

  1. Add a new file in the routes folder called <inline-code>+scope.js<inline-code>
  2. Paste the following code into <inline-code>routes/+scope.js<inline-code>:

This will allow requests from ANY domain! For your actual, production app, you probably want to set the <inline-code>origin<inline-code> option to a specific domain - the domain of your store. Read more about CORS in Gadget in our documentation.

Your route is now complete! Now all that is needed is a frontend app that allows shoppers to ask a question and displays the response along with product recommendations.

Step 7: Use Shopify theme app extension to embed chatbot

We make use of an app embed block for our storefront chatbot theme extension. This means that our extension works with any Shopify theme, both vintage and Online Store 2.0 themes.

  1. Use git to clone the Shopify CLI app
  2. <inline-code>cd<inline-code> to the cloned directory
  3. Run <inline-code>yarn install<inline-code> to install dependencies
  4. Update the direct script tag in <inline-code>extensions/theme-extension/blocks/chatbot.liquid<inline-code> to include your app's script tag URL
The script tag URL can be found in the Installing section of your app's API Reference.Your script tag needs --development added to your app-specific subdomain when working on your Development environment.
  1. Run <inline-code>yarn dev<inline-code> to start your app and connect to your existing Partners app and development store

You should now be set up and ready to add the chatbot theme app extension to the storefront theme.

  1. Navigate to your storefront theme editor and click on App embeds in the left sidebar
  2. Enable your app - the chatbot should appear in your storefront preview
  3. Click Save in the top right corner of the page

Your chatbot should now be available in your storefront - try it out!

Screenshot of the finished chatbot, with a question entered (asking about snowboards for sale) and a response. The response includes a text response and product recommendations.

Next steps

You now have a chatbot that can respond to shopper questions with product recommendations! You can continue to build on this app by:

  • customizing the embedded React frontend, found in the frontend folder, to give merchants installation instructions
  • editing the prompt in <inline-code>routes/POST-chat.js<inline-code> to customize the chatbot's response
  • change the look, feel, and merchant customization options for the chatbot by editing the theme extension files
  • maintain full chat context by passing <inline-code>messages<inline-code> back and forth between the client and server
  • also maintain chat context between browser sessions and/or windows by storing the full chat context in the database

Have questions about the tutorial? Join Gadget's developer Discord to ask Gadget employees and join the Gadget developer community!

Want to learn more about building AI apps in Gadget? Check out our building AI apps documentation.

Interested in learning more about Gadget?

Join leading agencies making the switch to Gadget and experience the difference a fullstack platform can make.

Keep reading

No items found.
Keep reading to learn about how it's built

Under the hood

Theme extension overview

Theme extensions allow you to create custom blocks that merchants can place in the storefront theme editor. You can read more about theme extensions in the Shopify docs. This chatbot extension is an app embed block, so it works with both vintage and Online Store 2.0 themes.

In this theme there are 3 main files:

  • <inline-code>blocks/chatbot.liquid<inline-code> - the main file that renders the chatbot
  • <inline-code>assets/chatbot.js<inline-code> - handles the chatbot logic and calls your Gadget app's API
  • <inline-code>assets/chatbot.css<inline-code> - the CSS file that styles the chatbot
We're on Discord, drop in and say hi!
Join Discord
Bouncing Arrow