How To Setup Gatsby With Headless Shopify

Integrating Shopify with Gatsby allows you to create a fast, dynamic, and highly customisable storefront.

GatsbyFramework
ShopifyE-Commerce

Tom McCulloch

Read Time: 5 min

Create Gatsby Project

First, you need to create a new Gatsby project. If you don't have Gatsby CLI installed, you can install it globally using npm or yarn:

npm install -g gatsby-cli

Create a new Gatsby project:

gatsby new gatsby-shopify-store
cd gatsby-shopify-store

Install Necessary Plugins

Install the gatsby-source-shopify plugin and other necessary dependencies:

npm install gatsby-source-shopify dotenv gatsby-plugin-react-helmet

Finding Your Shopify Store Name

Log in to your Shopify Admin Panel:

  • Go to Shopify and log in with your store's credentials.

Locate Your Store Name:

  • Your store name is typically the subdomain used for your store. For example, if your Shopify store's URL is https://my-awesome-store.myshopify.com, then your store name is my-awesome-store.

Generating Your Storefront API Access Token

Navigate to Apps:

  • In the Shopify admin panel, click on the Apps section in the left sidebar.

Manage Private Apps:

  • Scroll down to the bottom of the Apps page and click on the Manage private apps link.

Create a New Private App:

  • Click on the Create a new private app button.

Configure Your Private App:

  • Private app name: Give your private app a name, such as Gatsby Storefront .Contact email: Provide your email address.

Set API Permissions:

  • In the Admin API section, find the Storefront API section and check the box to enable Allow this app to access your storefront data using the Storefront API. Under Storefront API permissions, ensure that you select the necessary permissions for your Gatsby site, such as Read product and customer data.

Save Your Private App:

  • Click the Save button at the top right. After saving, you will be redirected to a page with your API credentials.

Copy the Storefront API Access Token:

  • On the app details page, you will see a section for Storefront API access token. Copy this token.

Configure Environment Variables

Create a .env file in the root of your project and add your Shopify store details, ensure these start with GATSBY_ otherwise you will have issues:

GATSBY_SHOPIFY_STORE_NAME=your-store-name.myshopify.com
GATSBY_SHOPIFY_ACCESS_TOKEN=your-storefront-access-token

Configure gatsby-config.js

Update your gatsby-config.js file to include the gatsby-source-shopify plugin:

require("dotenv").config({
  path: `.env`,
});

module.exports = {
  siteMetadata: {
    title: "Gatsby Shopify Store",
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-shopify`,
      options: {
        shopName: process.env.GATSBY_SHOPIFY_STORE_NAME,
        accessToken: process.env.GATSBY_SHOPIFY_ACCESS_TOKEN,
        shopifyConnections: ["collections"],
        downloadImages: false,
        apiVersion: "2024-01",
      },
    },
  ],
};

Fetch Data with GraphQL

Once you have configured the plugin, you can fetch data from your Shopify store using GraphQL. Start your development server:

gatsby develop

Open the GraphiQL interface at http://localhost:8000/___graphql and run the following query to fetch products:

{
      allShopifyProduct {
        nodes {
          shopifyId
          handle
          title
          vendor
          featuredImage {
            src
          }
          variants {
            shopifyId
            title
            image {
              src
            }
            price
          }
          priceRangeV2 {
            maxVariantPrice {
              amount
            }
          }
          descriptionHtml
          productType
          metafields {
            namespace
            key
            value
          }
        }
      }
    }
  `);

Create StoreContext.js

To manage the state of your store, such as cart and checkout, create a StoreContext.js file in the src/context directory:

import React, { useState, createContext, useEffect } from 'react';
import Client from 'shopify-buy';

const client = Client.buildClient({
  domain: process.env.GATSBY_SHOPIFY_STORE_NAME,
  storefrontAccessToken: process.env.GATSBY_SHOPIFY_ACCESS_TOKEN,
});

const defaultValues = {
  cart: [],
  client,
  checkout: {
    lineItems: [],
  },
  updateCheckout: () => {},
};

export const StoreContext = createContext(defaultValues);

const StoreProvider = ({ children }) => {
  const [checkout, setCheckout] = useState(defaultValues.checkout);

  useEffect(() => {
    const initializeCheckout = async () => {
      const newCheckout = await client.checkout.create();
      setCheckout(newCheckout);
    };

    initializeCheckout();
  }, []);

  const updateCheckout = (newCheckout) => {
    setCheckout(newCheckout);
  };

  return (
    <StoreContext.Provider value={{ ...defaultValues, checkout, updateCheckout }}>
      {children}
    </StoreContext.Provider>
  );
};

export default StoreProvider;

Wrap Root Element with StoreProvider

Wrap your root element with the StoreProvider in gatsby-browser.js and gatsby-ssr.js:

import React from "react";
import StoreProvider from "./src/context/StoreContext";

export const wrapRootElement = ({ element }) => (
  <StoreProvider>{element}</StoreProvider>
);

Create Product and Cart Components

import React, { useContext } from 'react';
import { graphql, useStaticQuery } from 'gatsby';
import { StoreContext } from '../context/StoreContext';

const ProductListing = () => {
  const data = useStaticQuery(graphql`
    query {
      allShopifyProduct {
        nodes {
          shopifyId
          handle
          title
          vendor
          featuredImage {
            src
          }
          variants {
            shopifyId
            title
            image {
              src
            }
            price
          }
          priceRangeV2 {
            maxVariantPrice {
              amount
            }
          }
          descriptionHtml
          productType
          metafields {
            namespace
            key
            value
          }
        }
      }
    }
  `);

  const { client, checkout, updateCheckout } = useContext(StoreContext);

  const addToCart = async (variantId) => {
    const lineItemsToAdd = [
      {
        variantId,
        quantity: 1,
      },
    ];
    const newCheckout = await client.checkout.addLineItems(checkout.id, lineItemsToAdd);
    updateCheckout(newCheckout);
  };

  return (
    <div>
      {data.allShopifyProduct.nodes.map((product) => (
        <div key={product.shopifyId}>
          <h2>{product.title}</h2>
          <div dangerouslySetInnerHTML={{ __html: product.descriptionHtml }} />
          {product.featuredImage && (
            <img src={product.featuredImage.src} alt={product.title} />
          )}
          <p>{product.variants[0].price}</p>
          <button onClick={() => addToCart(product.variants[0].shopifyId)}>
            Add to Cart
          </button>
        </div>
      ))}
    </div>
  );
};

export default ProductListing;

Cart Component:

import React, { useContext } from 'react';
import { StoreContext } from '../context/StoreContext';

const Cart = () => {
  const { checkout } = useContext(StoreContext);

  return (
    <div>
      <h2>Cart</h2>
      {checkout.lineItems.length ? (
        checkout.lineItems.map((item) => (
          <div key={item.id}>
            <p>{item.title}</p>
            <p>{item.quantity}</p>
            <p>{item.variant.price}</p>
          </div>
        ))
      ) : (
        <p>Your cart is empty</p>
      )}
    </div>
  );
};

export default Cart;

Use Components in Pages

Finally, use the ProductListing and Cart components in your pages.

import React from 'react';
import ProductListing from '../components/ProductListing';
import Cart from '../components/Cart';

const IndexPage = () => (
  <div>
    <h1>Welcome to the Gatsby Shopify Store</h1>
    <ProductListing />
    <Cart />
  </div>
);

export default IndexPage;

Conclusion

By following these steps, you have set up a Gatsby project integrated with Shopify, created a context for managing state, and built basic components for displaying products and a cart. This setup provides a strong foundation for building a dynamic, high-performance e-commerce site with Gatsby and Shopify.