Integrating a headless CMS with Shopify Hydrogen
You can easily integrate Hydrogen with a headless CMS and we’ll show you how with Hygraph.
You might want to build your online storefront using a headless CMS for several reasons. You might wish to greater customization of your website, faster server-side rendering, smart caching, or progressive hydration.
Built on top of Remix, Shopify's full-stack web framework, Hydrogen, is a headless framework that allows you to develop and deliver custom storefronts for your Shopify site. You can easily integrate Hydrogen with a headless CMS, and we’ll show you how with Hygraph.
What is Shopify Hydrogen?Anchor
Before jumping into the step-by-step tutorial, let's back up and explain what Shopify Hydrogen is.
You already know Hydrogen is a headless framework. By default, it’s designed to work with Remix, but it provides a React library that’s portable to other supporting frameworks. Hydrogen's integrated storefront API client lets you accelerate your eCommerce development with pre-built components, utilities, and hooks.
Some of the key benefits of Hydrogen include:
- Customization: Build a highly customized Shopify storefront without relying on pre-built themes or templates. Complete control over the design and functionality of your website means you can create a unique user experience for your brand.
- Fast server-side rendering: Hydrogen renders pages on the server side, which can significantly reduce page load times. That’s especially important for eCommerce sites, where slow loading can mean frustrated customers or lost sales.
- Improved SEO: Server-side rendering improves SEO by making it easier for search engines to crawl and index your site. This means your site is more likely to appear at the top of search engine results pages, which can drive traffic and increase sales.
- Greater flexibility: Hydrogen offers more control over your storefront than traditional Shopify themes or templates, so you can easily customize your site to meet the unique needs of your business. You can also make changes quickly and easily as your business evolves.
Building a headless content platform with Shopify Hydrogen and HygraphAnchor
To follow along with this tutorial, you need to have the following lined up:
- A Hygraph account and a Shopify account.
- A Hygraph project named
Hygraph Shopify Store
with a model namedProduct
. - A Shopify store named
Hygraph-Hydrogen Store
with at least two products. You can add any two products, but if you want to use the same data as this tutorial, you can add these. - Node.js v16 or later and npm v7 or later installed on your local machine.
- A web browser and code editor.
Installing Shopify for HygraphAnchor
On your Hygraph project dashboard, select Apps from the sidebar and click Go to Marketplace.
From the Hygraph marketplace, select Shopify.
On the Shopify app description page, click Install Shopify for Hygraph.
On the app installation page, select your project and environment and click Install app.
On the app permission authorization page, click Authorize app.
On the Shopify configuration page, fill out the store token and the store domain and click Save. You can find more information about how to access these details from the helper links provided on the page. Take note of the values—you’ll use them later on.
Click Schema in the sidebar and ensure the *Product model is selected.
You can now go ahead and add some fields. Select Shopify product picker as the field type, provide the display name, and click Add. With this field, you can select products from Shopify.
Next, create a Single line text field with the display name color
. This field stores the color of the product.
.
Your Product model page should now look like this:
Adding content to the product modelAnchor
To add some content to the model that you just created, select Content from the sidebar and click Add entry.
On the new product page, click Select product from Shopify to select a product. Make sure you also provide a color for your product.
Click Save & publish to push the product to the published stage so that it can be retrieved from the API endpoint. Do this for all your products.
Your Product content page should now look like this:
Select API playground from the sidebar and run the Products
query to check whether the products you previously added can be retrieved. If the query returns some data, everything is working as expected, and you can move on to enable API access.
Enable API access. This guide enables full public API access, though you can secure your API with permanent auth tokens. Copy the content API endpoint—you’ll use it later.
Creating the Hydrogen storefrontAnchor
To create a new Hydrogen storefront, run the following command in the terminal:
npm create @shopify/hydrogen@latest
Choose Hello World
as your template, JavaScript
for the language, hydrogen-hygraph-storefront
for the app location, and select Yes
to install dependencies with npm.
Next, change into the hydrogen-hygraph-storefront
directory and run npm run dev
to confirm that the project was successfully created and all the dependencies installed. Open http://localhost:3000
on your browser, and you should see the following page:
You must now configure your storefront token in the .env
file. Open the .env
file in the project root folder and replace the PUBLIC_STOREFRONT_API_TOKEN
and PUBLIC_STORE_DOMAIN
values with the Shopify store credentials that you obtained when configuring the Shopify app in the Hygraph CMS.
Configuring Tailwind and creating the layoutAnchor
You need to configure Tailwind CSS to apply basic styling to the storefront. Execute the following command to install Tailwind CSS and the dependencies it relies on:
npm install -D tailwindcss postcss postcss-cli autoprefixer concurrently
Run the command npx tailwindcss init -p
to generate the Tailwind CSS configuration files tailwind.config.js
and postcss.config.js
. Open tailwind.config.js
and replace the existing code with the code below that points Tailwind to all the template files:
/** @type {import('tailwindcss').Config} */module.exports = {content: ["./app/**/*.{js,ts,jsx,tsx}",],theme: {extend: {},},plugins: [],}
Create a file named tailwind.css
in the app/styles
folder and add the following Tailwind directives:
@tailwind base;@tailwind components;@tailwind utilities;
Open the package.json
file and replace the dev
and build
scripts with the following scripts, which will build your development and production Tailwind CSS:
"build": "npm run build:css && shopify hydrogen build --entry ./server","build:css": "postcss app/styles/tailwind.css -o app/styles/tailwind-build.css --env production","dev": "npm run build:css && concurrently -g -r npm:dev:css \"shopify hydrogen dev\"","dev:css": "postcss app/styles/tailwind.css -o app/styles/tailwind-build.css -w",
To configure the page layout, create a file named Layout.jsx
in the app/components
folder and add the code below:
export function Layout({children, title}) {return (<div className="flex flex-col min-h-screen"><headerrole="banner"className="flex items-center justify-between w-full h-16 p-6 sticky top-0 gap-4 shadow-sm"><div className="flex gap-8"><a className="font-bold" href="/">{title}</a></div></header><mainrole="main"id="mainContent"className="flex-grow p-6">{children}</main></div>);}
The Layout.jsx
file ensures the display is consistent on all pages by displaying a header at the top and rendering the other content in the main
tags.
Next, open the app/root.jsx
file and replace the existing code with the following:
import {Links,Meta,Outlet,Scripts,ScrollRestoration,useLoaderData,} from '@remix-run/react';import favicon from '../public/favicon.svg';import tailwind from './styles/tailwind-build.css'import { Layout } from './components/Layout';export const links = () => {return [{rel: 'stylesheet', href: tailwind},{rel: 'preconnect',href: 'https://cdn.shopify.com',},{rel: 'preconnect',href: 'https://shop.app',},{rel: 'icon', type: 'image/svg+xml', href: favicon},];};export const meta = () => ({charset: 'utf-8',viewport: 'width=device-width,initial-scale=1',});export async function loader({context}) {const layout = await context.storefront.query(LAYOUT_QUERY);return {layout};}export default function App() {const data = useLoaderData();const {name: shopName} = data.layout.shop;return (<html lang="en"><head><Meta /><Links /></head><body><Layout title={shopName}><Outlet /></Layout><ScrollRestoration /><Scripts /></body></html>);}const LAYOUT_QUERY = `#graphqlquery layout {shop {namedescription}}`;
The code above imports the Tailwind build and wraps the entire application with the Layout
component that you created previously. It also retrieves your Shopify store name and passes it to the Layout
component as a prop to display as a page title.
Fetching and displaying the products.Anchor
To fetch and display all the products that you added to your Shopify store, create a file named index.js
in the app/routes
folder and add the code below:
import { useLoaderData } from '@remix-run/react';import { Image } from '@shopify/hydrogen';export const meta = () => {return {title: 'Hydrogen',description: 'A custom storefront powered by Hydrogen'};};// query to fetch all products from Hygraphconst getAllProductsFromHygraph = `query Products {products {idproductIdcolor}}`;// query to fetch all products from Shopifyconst getAllProductsFromShopify = `#graphqlquery products($ids: [ID!]!) {nodes(ids: $ids) {...on Product {idtitlehandlefeaturedImage {urlwidthheight}descriptionpriceRange {minVariantPrice {amount}}}}}`export async function loader({ context }) {// fetch the products from Hygraphconst response = await fetch('<your-hygraph-content-api-endpoint>', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ query: getAllProductsFromHygraph })});const { data } = await response.json();// extract the product IDs from the Hygraph response and push them into an arrayconst productsArray = data?.products.map(prod => prod.productId)// query the Shopify storefront for the products info and pass the array containing the product IDsconst res = await context.storefront.query(getAllProductsFromShopify, {variables: {ids: productsArray}})// return the data fetched from Hygraph and Shopify// products => the data fetched from Shopify// data => the data fetched from Hygraphreturn { products: res.nodes, data: data.products }}export default function Index() {const { products, data } = useLoaderData();return (<section className="w-full gap-4"><h2 className="font-bold text-2xl mb-4">Products</h2><div className="flex space-x-6">{/* Loop through the products and display the necessary info */}{products.map((product, i) => {return (<div key={product.id} className="grid gap-4">{product?.featuredImage && (<div className='h-64 w-96'><Imagealt={`Image of ${product.title}`}data={product.featuredImage}className='w-full h-full object-cover rounded'/></div>)}<h2 className="whitespace-pre-wrap max-w-prose font-medium text-copy"><span>{product.title} {' • '}</span><span className='text-sm text-gray-500'>{product.id === data[i].productId && `${data[i].color}`} {' • '}</span><span>Kshs. {product.priceRange.minVariantPrice.amount}</span></h2></div>);})}</div></section>);}
The code above defines two queries: getAllProductsFromHygraph
, which specifies the data to be fetched from Hygraph; and getAllProductsFromShopify
, which specifies the data to be fetched from Shopify.
A Remix loader function fetches data from the Hygraph Content API endpoint using the getAllProductsFromHygraph
query. It loops through the Hygraph response, extracts the productId
field from each object, and pushes the values of these fields into the productsArray
array.
The loader function uses Hydrogen's storefront
param to query the Shopify storefront using the getAllProductsFromShopify
query and passing the productsArray
as a variable. This retrieves all the products whose ID is defined in the productsArray
variable.
The code loops through the products
array, which contains the products fetched from the Shopify storefront, and renders the necessary data. It also renders the custom field color
, which you defined in the Hygraph CMS.
Editor's Note
Be sure to replace <your-hygraph-content-api-endpoint>
with your own API endpoint.
Testing the final applicationAnchor
To test whether the integration is successful, execute npm run dev
in your terminal to start a local development server and navigate to http://localhost:3000
on your browser. If you used the two products from this tutorial’s repo, you should see the following:
The rendered webpage shows the product image, title, and price fetched from Shopify. The product color was fetched from Hygraph.
In brief:
- You fetch the IDs of the products from Hygraph.
- You use the IDs to specify the products to fetch from your Shopify store.
- You display all the product details by combining the data fetched from Hygraph and Shopify.
Editor's Note
Note that you can check out all the code in this article on GitHub.
ConclusionAnchor
Hydrogen gives you significantly more flexibility and customization over your Shopify storefront. Integrate it with a federated content management platform like Hygraph, and you’ve got a headless content platform that can evolve with your eCommerce application as quickly as your users need you to.