Need help with setting up your e-commerce store? Try our managed ecommerce platform.
Learn More

How to integrate Gatsby with Shopify Store

Integrate your Shopify Store with Gatsby Site, build e-commerce website using Gatsby and Shopify

Posted by Jitendra Nirnejak on 11 Feb 2021
How to integrate Gatsby with Shopify Store

Whether you're starting your e-commerce journey or planning to shift your whole business online, Shopify is a great place to start. And as your business evolves Shopify has all the resources to help you grow along with it. It takes the pain of setting up the store, authentication, payment, etc., and lets you focus on the do your business.

But when it comes to customizing a Shopify Store. Your options are very limited. It is also very difficult if you want to extend your store. Or want to add more pages but with custom design or manage other aspects of your site somewhere else.

Solution

One great way to overcome these issues is to set up and manage your store on Shopify but have a separate front-end built using any static site generator, and Gatsby stands out to be one of the best options. Here we're going to look at how can we integrate a Gatsby website with Shopify to show products and enable users to make purchases as well.


Setup your store

If you already haven't set up your Shopify store you need to do that first. Add your products, build your collections, and do all the basic setup needed.

Create Private App

Once your store setup is done you need to create a private app in your Shopify Store. You must have admin access to do this step. This private app will let you access your products and cart from the Gatsby Site.

To Create a private app you need to navigate to Apps Section of your store.

Shopify Menu
Shopify Menu

then goto Manage Private Apps link.

Shopify Apps
Shopify Apps

Then click on Create Private Apps

Shopify Private Apps
Shopify Private Apps

Now Enter Private app name, down at the end of the page you need to check Allow this app to access your storefront data using the Storefront API. Then click on the Save button. That will generate a Storefront access token. That's the token we'll need to set up our front-end. So keep that safe 😉

Now that's done we can start with integrating Gatsby with our Shopify Store.


Gatsby Integration

We'll start with GraphQL Integration to build the pages for our products.

Install required packages

npm install gatsby-source-shopify shopify-buy

Gatsby Config

{
  resolve: `gatsby-source-shopify`,
  options: {
    // The domain name of your Shopify shop.
    shopName: `my-store`,
    // The storefront access token
    accessToken: `c1cba2ee5e15c77f26904b030369aln2`,
  },
},

Now once the setup is done you should be able to query your products from GraphiQL or GraphQL Playground(learn how to use GraphQL Playground as default explorer in Gatsby).

Start your development server(you might need to clear your cache) and head out to http://localhost:8000/__graphql.

GraphQL Playground with Shopify Store Queries
GraphQL Playground with Shopify Store Queries

Build your template

Now that you have figured out the available queries and options to fetch your data, It's time to build a template to render your products.

import React from "react"
import { graphql } from "gatsby"
import PropTypes from "prop-types"

import SEO from "../components/seo"

import ProductDescription from "../components/Product/ProductDescription"

const Product = ({ data }) => {
  const { shopifyProduct, allShopifyProduct } = data

  return (
    <React.Fragment>
      <SEO path={shopifyProduct.handle} title={shopifyProduct.title} />
      <ProductDescription shopifyProduct={shopifyProduct} />
    </React.Fragment>
  )
}

export const postQuery = graphql`
  query ShopifyProductById($id: String!) {
    shopifyProduct(id: { eq: $id }) {
      id
      shopifyId
      handle
      title
      tags
      descriptionHtml
      publishedAt
      productType
      priceRange {
        minVariantPrice {
          amount
          currencyCode
        }
        maxVariantPrice {
          amount
          currencyCode
        }
      }
      variants {
        title
        shopifyId
        price
        priceV2 {
          amount
          currencyCode
        }
        selectedOptions {
          name
          value
        }
      }
      images {
        id
        originalSrc
      }
    }
  }
`

Product.propTypes = {
  data: PropTypes.object.isRequired,
}

export default Product

Build Product Pages

We can use these queries to fetch our products and build pages from our template. If you want to skip build for any of the pages you can do that as well.

// gatsby-node.js

const path = require("path")

const query = `
{
  allShopifyProduct {
    edges {
      node {
        id
        handle
      }
    }
  }
}
`
exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  const res = await graphql(query)
  res.data.allShopifyProduct.edges.map(edge => {
    createPage({
      path: `/shop/${edge.node.handle}/`,
      component: path.resolve("./src/templates/product.js"),
      context: {
        id: edge.node.id,
      },
    })
  })
}

After this, your need to start/restart your Gatsby Development server, which will generate all of your products pages.

Now that our product pages are built let's start with integrating Shopify Buy SDK to add Dynamic Functionality


Shopify Buy SDK(Dynamic Functionality)

Using the gatsby-source-shopify we have successfully built our product pages. But that will not work if we want to add any dynamic functionality like shopping cart, search, etc. To add dynamic functionality we need to add and integrate shopify-buy SDK.

In your layout file of your project you can import and initialise the SDK

/*.  src/layout/index.   */

import React from "react"
import PropTypes from "prop-types"
import Client from "shopify-buy"

class Layout extends React.Component {
  componentDidMount() {
    this.client = Client.buildClient({
      domain: "my-store.myshopify.com",
      storefrontAccessToken: "c1cba2ee5e15c77f26904b030369aln2",
    })
    this.client.checkout.create().then(checkout => {
      // Do something with the checkout
      this.setState({ checkout })
    })
  }

  // add your methods here

  render() {
    // return JSX
  }
}

The client object in our layout will have access to our Shopify store. Using that we can add various dynamic features. Let's look at how we can implement cart functionality using Shopify buy SDK.

Cart Integration

Initialise required state variables

state = {
  isCartOpen: false, // to show cart when any product is added
  cartRequest: false,
  checkout: { lineItems: [] },
  products: [],
  shop: {},
}

Add methods to add product to cart, remove product from cart and update quantity

_addVariantToCart(variantId, quantity) {
  this.setState({ isCartOpen: true, cartRequest: true })

  if (variantId.indexOf('Shopify__ProductVariant__') !== -1)
    variantId = variantId.split('Shopify__ProductVariant__')[1]

  const lineItemsToAdd = [{variantId, quantity: parseInt(quantity, 10)}]
  const checkoutId = this.state.checkout.id

 return this.client.checkout.addLineItems(checkoutId, lineItemsToAdd)
    .then(checkout => this.setState({ checkout, cartRequest: false }))
}

_updateQuantityInCart(lineItemId, quantity) {
  const checkoutId = this.state.checkout.id
  const lineItemsToUpdate = [{id: lineItemId, quantity: parseInt(quantity, 10)}]
  this.setState({ isCartOpen: true, cartRequest: true })
  return this.client.checkout.updateLineItems(checkoutId, lineItemsToUpdate)
    .then(checkout => this.setState({ checkout, cartRequest: false }))
}

_removeLineItemInCart(lineItemId) {
  const checkoutId = this.state.checkout.id
  this.setState({ isCartOpen: true, cartRequest: true })
  return this.client.checkout.removeLineItems(checkoutId, [lineItemId])
    .then(checkout => this.setState({ checkout, cartRequest: false }))
}

Once all your methods and states are defined you need to pass them down to your page components to make them accessible.

render() {
  let { children } = this.props
  const { checkout, isCartOpen, cartRequest } = this.state

  children = React.Children.map(children, (child) =>
    React.cloneElement(child, {
      addVariantToCart: this._addVariantToCart.bind(this),
      updateQuantityInCart: this._updateQuantityInCart.bind(this),
      removeLineItemInCart: this._removeLineItemInCart.bind(this),
      checkout: checkout,
    })
  )
  return (
    <React.Fragment>
      <Header
				cartRequest={cartRequest}
				cartCount={checkout.lineItems.length}
			/>
      <main>{ children }</main>
      <Footer />
    </React.Fragment>
  )
}

Final File

/* Your site layout file
 -> src/layout/index.js
*/

import React from "react"
import PropTypes from "prop-types"
import Client from "shopify-buy"

import Header from "../components/header"
import Footer from "../components/footer"

import "../assets/scss/main.scss"

class Layout extends React.Component {
  state = {
    isCartOpen: false,
    cartRequest: false,
    checkout: { lineItems: [] },
    products: [],
    shop: {},
  }
  componentDidMount() {
    this.client = Client.buildClient({
      domain: "my-store.myshopify.com",
      storefrontAccessToken: "c1cba2ee5e15c77f26904b030369aln2",
    })
    this.client.checkout.create().then(checkout => {
      // Do something with the checkout
      this.setState({ checkout })
    })
  }
  _addVariantToCart(variantId, quantity) {
    this.setState({ isCartOpen: true, cartRequest: true })

    if (variantId.indexOf("Shopify__ProductVariant__") !== -1)
      variantId = variantId.split("Shopify__ProductVariant__")[1]

    const lineItemsToAdd = [{ variantId, quantity: parseInt(quantity, 10) }]
    const checkoutId = this.state.checkout.id

    return this.client.checkout
      .addLineItems(checkoutId, lineItemsToAdd)
      .then(checkout => this.setState({ checkout, cartRequest: false }))
  }

  _updateQuantityInCart(lineItemId, quantity) {
    const checkoutId = this.state.checkout.id
    const lineItemsToUpdate = [
      { id: lineItemId, quantity: parseInt(quantity, 10) },
    ]
    this.setState({ isCartOpen: true, cartRequest: true })
    return this.client.checkout
      .updateLineItems(checkoutId, lineItemsToUpdate)
      .then(checkout => this.setState({ checkout, cartRequest: false }))
  }

  _removeLineItemInCart(lineItemId) {
    const checkoutId = this.state.checkout.id
    this.setState({ isCartOpen: true, cartRequest: true })
    return this.client.checkout
      .removeLineItems(checkoutId, [lineItemId])
      .then(checkout => this.setState({ checkout, cartRequest: false }))
  }

  render() {
    let { children } = this.props
    const { checkout, isCartOpen, cartRequest } = this.state

    children = React.Children.map(children, child =>
      React.cloneElement(child, {
        addVariantToCart: this._addVariantToCart.bind(this),
        updateQuantityInCart: this._updateQuantityInCart.bind(this),
        removeLineItemInCart: this._removeLineItemInCart.bind(this),
        checkout: checkout,
      })
    )
    return (
      <React.Fragment>
        <Header
          cartRequest={cartRequest}
          cartCount={checkout.lineItems.length}
        />
        <main>{children}</main>
        <Footer />
      </React.Fragment>
    )
  }
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout

Now, these methods will be accessible from your Header and Page components, all your need to do is call these methods and all the dynamic functionality will be added. This API is compatible with Gatsby Source API so you can use the same product id, field names etc.


Hope this article helped you in building your e-commerce store by integrating your Shopify Store into your Gatsby Site. I would encourage you to check out full documentation of Gatsby Source Shopify to learn more about available GraphQL Queries to fetch product collections, terms and conditions, pages, and other types of content from your store. You can also checkout Shopify Buy SDK in detail to learn about available methods and features in the API.


Gatsby Shopify Plugin : https://www.gatsbyjs.com/plugins/gatsby-source-shopify/

Shopify Buy SDK: https://www.npmjs.com/package/shopify-buy

Shopify Storefront API: https://shopify.dev/tools/libraries/storefront-api/javascript

- Jitendra Nirnejak


Need help with setting up your e-commerce store? Try our managed ecommerce platform.
Learn More

Have a Project in mind?