Distribute NFTs on a Shopify Store

Distribute NFTs on a Shopify Store

In this guide, we'll show you how you can sell digital assets as NFTs using Shopify and thirdweb. By the end, users will be able to enter their wallet address as a custom field of your Shopify product and purchase the NFT using FIAT currency.

Access the full source code.

Note: Merchants who are using thirdweb for distributing NFTs via Shopify need approval from Shopify to sell NFTs. Learn More or contact blockchain@shopify.com for more info.

Application Design

We'll be using a server-side application to mint NFTs to the wallet address the user specifies. An overview of the application design can be found below:

image.png

We'll first add a custom field to our product pages on Shopify to allow users to enter their wallet addresses. For each product, we'll upload the same metadata that we did for our NFTs; as well as the same supply for each NFT. This way, we'll have a Shopify product for each NFT that we want users to be able to mint.

Users will be able to purchase the "product" from Shopify, using FIAT currency. When this happens, our application running on a server will be informed of a new purchase, at which point it will read the user's wallet address and mint the NFT to their wallet.

Let's get into it!

Creating the NFT Collection

We'll be using thirdweb's prebuilt contracts to build our NFT collection. In this guide, we'll be using the NFT Collection contract which supports ERC-721 NFTs.

Head to the thirdweb dashboard and connect your wallet.

image.png

Click Deploy New Contract and select the NFT Collection contract. Here, you can configure the metadata of the smart contract itself:

image.png

Great! Now we're ready to build out our server application and start minting NFTs!

Creating the Server

We'll be building out our application in Node.js. So let's initialize a new Node project:

npm init -y

Next, let's install both the thirdweb SDK and Shopify SDK as well as some additional packages we'll be using on our server.

npm install @shopify/shopify-api @thirdweb-dev/sdk crypto dotenv ethers express raw-body

Create a new file called index.js at the root of your project, where we'll write the core logic to listen for Shopify purchase events and mint NFTs.

const express = require("express");
const app = express();
const getRawBody = require("raw-body");
const crypto = require("crypto");
require("dotenv").config();
const secretKey = process.env.SHOPIFY_SECRET_KEY;

// Listen for requests to the /webhooks/orders/create route
app.post("/webhooks/orders/create", async (req, res) => {
  console.log("Order event received!");

  // Below, we're verifying the webhook was sent from Shopify and not a potential attacker
  // Learn more here: https://shopify.dev/apps/webhooks/configuration/https#step-5-verify-the-webhook
  const hmac = req.get("X-Shopify-Hmac-Sha256");
  const body = await getRawBody(req);
  const hash = crypto
    .createHmac("sha256", secretKey)
    .update(body, "utf8", "hex")
    .digest("base64");

  // Compare our hash to Shopify's hash
  if (hash === hmac) {
    res.sendStatus(200);
  } else {
    res.sendStatus(403);
  }
});

app.listen(3000, () => console.log("Example app listening on port 3000!"));

Within this file, we're doing the following:

  • Listening for requests coming into the /webhooks/orders/create path
  • When a request comes in, we ensure the request is from Shopify using the webhook's signature (to avoid fake requests being sent to our endpoint).

Let's see how we can create the actual webhook from Shopify now.

Setting Up Shopify

If you don't already have one, you can follow Shopify's General checklist for starting a new Shopify Store to get started.

We'll assume you've already got a store for the purpose of this guide.

Creating A Webhook

Once your store is setup, you're ready to create a webhook. Head to Notification Settings:
image.png

Head down to the Webhooks section and click Create Webhook:

image.png

To create a Shopify webhook, we need to provide a URL to send the notifications to:

image.png

In a production application, you can host your server on any cloud platform, such as:

For local testing, you can use a library called localtunnel that exposes your localhost server to a public URL.

Minting NFTs

Firstly, let's set up our environment variables to use within our server in a .env file:

ADMIN_PRIVATE_KEY=xxx # The Private key of a wallet that has mint permissions in your NFT collection contract
NFT_COLLECTION_ADDRESS=xxx  # The Smart contract address of your NFT Collection
SHOPIFY_SECRET_KEY=xxx # Your Shopify Signature Key (Outlined below)
SHOPIFY_SITE_URL=xxx # Your Shopify site URL  - e.g. xxx.myshopify.com
SHOPIFY_ACCESS_TOKEN=xxx # Your Shopify Access Token (Outlined below)

Getting Your Shopify Access Token

We'll be using the Shopify API to interact with our store programmatically. In order to do so, we need to generate an access token to connect to our store.

Create and install an admin application in our store by clicking Apps and selecting Apps and sales channel settings:

image.png

Click Develop Apps for your store to build a new app:

image.png

Click Create an app, and any information you choose for your application:

image.png

From the Configuration tab, click Configure on the Admin API integration and add the following scopes to your application:

image.png

Next, from the API Credentials tab, install the app we just created into your store:

image.png

Then, copy your Admin API Access token:

image.png

Getting Your Shopify Secret Key

You can find the secret key beneath where you created your Webhook in Shopify:

image.png

Back in our index.js, we first need to import the thirdweb and Shopify SDKs:

const { ThirdwebSDK } = require("@thirdweb-dev/sdk");
const { Shopify, DataType } = require("@shopify/shopify-api");

Then, inside of the hash === hmac block, we're going to iterate over each item the user purchased and mint the NFT to them:

// Compare our hash to Shopify's hash
  if (hash === hmac) {
    // Create a new client for the specified shop.
    const client = new Shopify.Clients.Rest(
      SHOPIFY_SITE_URL,
      SHOPIFY_ACCESS_TOKEN
    );

    const shopifyOrderId = req.get("X-Shopify-Order-Id");

    const response = await client.get({
      type: DataType.JSON,
      path: `/admin/api/2022-07/orders/${shopifyOrderId}.json`,
    });

    const itemsPurchased = response.body.order.line_items;

    const sdk = ThirdwebSDK.fromPrivateKey(
      // Learn more about securely accessing your private key: https://portal.thirdweb.com/sdk/set-up-the-sdk/securing-your-private-key
      ADMIN_PRIVATE_KEY,
      "goerli"
    );

    const nftCollection = await sdk.getEdition(NFT_COLLECTION_ADDRESS);

    // For each item purchased, mint the wallet address an NFT
    for (const item of itemsPurchased) {
      // Grab the information of the product ordered
      const productQuery = await client.get({
        type: DataType.JSON,
        path: `/admin/api/2022-07/products/${item.product_id}.json`,
      });

      // Set the metadata for the NFT to the product information
      const metadata = {
        name: productQuery.body.product.title,
        description: productQuery.body.product.body_html,
        image: productQuery.body.product.image.src,
      };

      // Mint the NFT
      const minted = await nftCollection.mintTo("<todo>", {
        metadata: metadata,
        supply: item.quantity,
      });

      console.log("Successfully minted NFTs!", minted);
    }

You'll notice in the above code, we're calling mintTo with an address of <todo>; that's because we need to add a custom field for users to enter their wallet address on our Shopify product pages.

Custom Wallet Address Field

Head to Themes under Sales Channels in the Shopify Admin sidebar.

Click Actions > Edit Code:

image.png

Edit the main-product.liquid file to include the below snippet:

<p class="line-item-property__field">
  <label for="walletAddress">Wallet Address:</label>
  <input id="walletAddress" type="text" name="properties[Wallet Address]" form="product-form-{{ section.id }}">
</p>

Your file should now look like this, remember to hit Save:

image.png

Now back in our index.js file, let's modify our placeholder todo logic with the following:

      const walletAddress = response.body.order.properties.find(
        (p) => p.name === "Wallet Address"
      ).value;

      // Mint the NFT
      const minted = await nftCollection.mintTo(walletAddress, metadata)

That's it! We're now ready to test out our store.

Testing Transactions

You can follow the Guide to Enabling Test Transactions to configure test transactions on your store.

Using one of the fake credit cards that Shopify provides in test mode, you can order a product from your store:

image.png

Once your purchase is processed, the webhook event is fired and caught by our server, which successfully mints the NFT to the user. It uses the information of the product as the metadata of the NFT.

image.png

We can also see the NFT has been minted to the user on the dashboard:

image.png

Conclusion

By utilizing Shopify's webhooks, we've set up a Node.js server that mints an NFT with the metadata of the product(s) the user purchased to their wallet! This way, whenever a user purchases a product on Shopify, we send them an NFT!

If you got stuck along the way, jump into our Discord channel to speak directly with our team!