A Shopify merchant needs an automated way to tag products being added to their Shopify store inventory. They source hundreds of products weekly from various dropshippers and upload the unstructured data to Shopify programmatically. Because the data is unstructured, Shopify is unable to power the merchant's storefront search. While the merchant can add tags inside the Shopify Admin, the experience of doing this on hundreds of products weekly is time-consuming.
To solve this, the merchant wants to build a custom Shopify app on Gadget that will run every new product description through an automated tagging script.
In this example, we'll build a custom product tagging app that listens to the product/create and product/updatewebhooks from Shopify, runs product descriptions through a tagging script, and sets tags back in Shopify.
Requirements
To get the most out of this tutorial, you will need:
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 and write scopes for the Shopify Products API, and select the underlying Product model
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.
Step 2: Add new model for tag keywords
The next step is to create a model that will store our list of vetted keywords that we can use to power our tagging script. These keywords can be different types of products or brands. Make sure to add keywords that will be found in your products' descriptions!
Click + next to the api/models folder in the nav to add a model, and call it allowedTag
Click + in the FIELDS section of the api/models/allowedTag/schema page to add a field, and name it keyword
Gadget instantly creates a new table and column in the underlying database and generates a GraphQL CRUD API for this model. Test it out the API in the API Playground!
Click on api/models/allowedTag/actions/create.js to open the allowedTag model's create action
Click the Run action button in the TRIGGERS panel on the right of the editor to open up the create action in the API Playground
Using the API Playground, we can make a create call to our allowedTag model to store a new keyword. The JS action is already set up to take a keyword as a parameter.
Enter a keyword to store in your database and run the action
We can also check to make sure our tag keywords have been saved.
Navigate to api/models/allowedTag/data to go to this model's data page
We can see our added allowedTag record!
Step 3: Build your tagging script
Gadget auto-generates a CRUD (create, read, update, delete) API for each of your models. For Shopify models, these create, update, and delete actions are triggered by Shopify webhooks.
Actions are customizable, and you can add code to the run and onSuccess functions. Read more about these functions in the Gadget actions docs.
Next, as add some code to the create action for the shopifyProduct model to tag products based on the keywords we have stored in the allowedTag model.
Navigate to api/models/shopifyProduct/actions/create.js
Paste the following code into the file:
api/models/shopifyProduct/actions/create.js
JavaScript
1import{
2 applyParams,
3 preventCrossShopDataAccess,
4 save,
5ActionOptions,
6}from"gadget-server";
7
8exportconst run:ActionRun=async({ params, record })=>{
26// merge with any existing tags and use Set to remove duplicates
27const finalTags =[
28...newSet(
29 newTags
30.filter((tag)=> allowedTags.includes(tag))
31.concat(record.tagsas string[])
32),
33];
34
35 logger.info(
36{ newTags, allowedTags, finalTags },
37`applying final tags to product ${record.id}`
38);
39
40// write tags back to Shopify
41const shopify = connections.shopify.current;
42if(shopify){
43await shopify.graphql(
44`mutation ($input: ProductInput!) {
45 productUpdate(input: $input) {
46 product {
47 tags
48 }
49 userErrors {
50 message
51 }
52 }
53 }`,
54{
55input:{
56id:`gid://shopify/Product/${record.id}`,
57tags: finalTags,
58},
59}
60);
61}
62}
63};
64
65exportconstoptions:ActionOptions={
66actionType:"create",
67};
That's not a lot of code!
This snippet will run on every incoming products/create webhook that is sent by Shopify, and determines if tags need to be added by cross-referencing the body of the incoming payload against the stored keyword records by making an internal API request to Gadget. Should any words match, they're sent back to Shopify as new tags for the product.
Gadget gives us a connections object as an argument to our effect function, which has an authenticated Shopify API client ready to go. We use this object to make API calls back to Shopify to update the tags and complete the process.
Sharing code between actions
If we want to run this same code on the update action, we can create a shared utility function to avoid duplicating code.
Create a new api/models/shopifyProduct/utils.js file:
Now this code will be run every time a product is created or updated in a Shopify store.
Avoid webhook loops
The record.changed helper is a special field that Gadget has included to help prevent an infinite loop when updating Shopify records.
When we call shopify.graphql(...) with the productUpdate mutation, the product in our Shopify store will be updated. This update action will fire Shopify's products/update webhook. If we are using this webhook as a trigger for running custom code that updates a product, we will be stuck in an endless loop of updating our products and running our action.
We can use record.changed to determine if changes have been made to the key on this record and only run our code if changes have occurred.
For more info on change tracking in Gadget, refer to the documentation.
Step 4: Access control
To ensure that only the right people can access your app, you can set up access control rules in Gadget. This will allow you to restrict access to certain parts of your app based on the user's role.
By default, merchants will not have access to your custom model APIs, such as allowedTag. You can grant permissions to the shopify-app-users role to allow merchants to access these APIs.
Navigate to the accessControl/permissions page
Grant the shopify-app-users role access to the allowedTag/ model's read, create, and delete actions
Now merchants will be able to manage allowedTag records from the embedded frontend in their Shopify store admin.
Step 5: Build a Shopify admin frontend
Gadget apps include a web folder for your frontend. This folder contains the following:
your Gadget API client in web/api.js
a default React app in web/main.jsx
router setup in web/App.jsx
two pages at web/routes/index.jsx and web/routes/about.jsx
Additional packages have also been added to your package.json upon connecting to Shopify:
@shopify/polaris: Shopify's design system components
@gadgetinc/react: provides React hooks for fetching data and calling your API
@gadgetinc/react/auto: provides autocomponents, pre-built forms and tables connected to your APIs
The entire tagger frontend code snippet is below. Additional details on some of Gadget's provided tooling are below the snippet.
Paste the following code into web/routes/index.jsx
The @gadgetinc/react/auto library provides autocomponents for your frontend. Autocomponents are pre-built configurable forms and tables that are wired up to your model actions.
Read the autocomponent guide for more information on autocomponent customization.
You don't need to use autocomponents in your frontends. Check out the Shopify frontends guide to learn how to manually read and write data.
If you go to your development app, you should now be able to test it out! Go back to the embedded frontend in your store admin and start adding custom tags. You'll be able to see the created tags in the allowedTag Data page in Gadget.
Congrats! You have built a full-stack and fully functional embedded product tagger application! Now you can test it out.
Step 6: Test it out
First, add some keywords to your product tagger. You want to make sure to add words that are in your product descriptions. If using Shopify's default store data, SUPER and DUPER both appear in the product description of The Complete Snowboard.
Go back to the Connections page in Gadget and click Shop Installs and then Sync on the connected store if you set up a custom app through the Partners dashboard, or just click Sync if you used the store Admin to set up your app.
Gadget will fetch each of the records in Shopify and run them through your actions. Not only will this populate your Gadget backend with the store's inventory, but it will also run the effects we added, updating the tags for each synced product. Our tagging application will also run on products when they are added to the store, so any new products will also be tagged for us automatically.
Congratulations! In about 20 minutes you were able to build a custom app that updates tags in Shopify each time there is a match against the list of allowed tags.
Next steps
Now that you can add keywords using an admin UI, you may want to try adding a global action to run through all existing products that have been synced to Gadget to apply tags!
Want to build apps that use Shopify extensions? Check out our pre-purchase checkout UI extension tutorial: