Use Shopify with Prismic
Learn how to build websites with Shopify and Prismic.
This guide shows how to integrate Shopify with Prismic to display products and collections in your content.
You’ll learn two approaches:
- Using Prismic’s built-in Shopify integration to select individual products.
- Creating a custom integration catalog using an API endpoint.
Both methods allow content writers to choose Shopify data directly from the Prismic editor while giving developers full control over how the data is displayed.
Prerequisites
Before you begin, you’ll need to set up Shopify API access for your store.
Create a Shopify custom app
Shopify requires custom apps for API access. Navigate to your Shopify admin and go to Settings > Apps and sales channels > Develop apps and click Create an app.
Use the following values when creating your app:
Field Value App Name ”Prismic Integration” (or your preferred name) Admin API access scopes Products: Read access Storefront API access scopes Products: Read access Click Create app and then Install app to finish setup.
Learn more about Shopify custom apps
Set up environment variables
After creating your app, save your Storefront API credentials as environment variables in a
.env
file:.env# Your Shopify store domain (without https://) SHOPIFY_STORE_DOMAIN=your-store-name.myshopify.com # Your Shopify Storefront API access token SHOPIFY_STOREFRONT_ACCESS_TOKEN=your_storefront_token_here
Select products in Prismic
Follow these steps when content writers need to select an individual product from a Shopify store.
Create a Shopify integration catalog
Prismic has a native integration to select products from a Shopify using an integration field.
To begin, follow the linked guide to create a Shopify integration field catalog.
Learn how to create a Shopify integration catalog
Add a product field to a content model
After creating the catalog, connect it to an integration field in a slice, page type, or custom type depending on where you need the product data.
Learn how to add an integration field
Display the product
The integration field provides basic product metadata. In some cases, content from the metadata is sufficient.
import { isFilled } from "@prismicio/client"; { isFilled.integration(slice.primary.product) && ( <div> <h3>{slice.primary.product.title}</h3> <p>{slice.primary.product.vendor}</p> <div dangerouslySetInnerHTML={{ __html: slice.primary.product.body_html }} /> </div> ); }
If you need additional product data, use Shopify’s Storefront API client.
npm install @shopify/storefront-api-client
This example shows how to fetch a product’s
title
andisGiftCard
properties using the Shopify Storefront API client.src/slices/FeaturedProduct/index.tsximport type { Content } from "@prismicio/client"; import { isFilled } from "@prismicio/client"; import type { SliceComponentProps } from "@prismicio/react"; import { createStorefrontApiClient } from "@shopify/storefront-api-client"; import type { ShopifyCollection } from "@/app/api/collections/route"; const shopify = createStorefrontApiClient({ storeDomain: `https://${process.env.SHOPIFY_STORE_DOMAIN}`, apiVersion: "2023-10", publicAccessToken: process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!, }); type FeaturedProductProps = SliceComponentProps<Content.FeaturedProductSlice>; // Using the App Router and a React Server Component, this component can fetch // data at render time on the server. export default async function FeaturedProduct({ slice }: FeaturedProductProps) { if (!isFilled.integration(slice.primary.product)) { return null; } // Fetch additional product data directly in the component. const product = await shopify.request( `#graphql query ($handle: String!) { product(handle: $handle) { title isGiftCard } } `, { variables: { handle: slice.primary.product.handle, }, }, ); return ( <div> <h3>{product.data?.product?.title}</h3> <p> {product.data?.product?.isGiftCard ? "This is a gift card." : "This is not a gift card."} </p> </div> ); }
You can type your Shopify GraphQL queries with GraphQL Codegen.
Add a product to a page
Test your new field by selecting a product in a page. If everything was set up correctly, you should see the product displayed on your page.
Product metadata
The product metadata matches what is provided by Shopify’s REST Admin API.
See the Product resource reference
Here is an example of what an integration field containing a Shopify product looks like from the Content API:
{
"id": 7234567890123,
"title": "Classic Leather Wallet",
"body_html": "<p>Handcrafted from premium full-grain leather, this classic bifold wallet combines timeless style with modern functionality. Features 8 card slots, 2 bill compartments, and RFID protection.</p>",
"vendor": "Premium Leather Co.",
"product_type": "Accessories",
"created_at": "2024-01-15T10:30:00-05:00",
"handle": "classic-leather-wallet",
"updated_at": "2024-11-20T14:45:30-05:00",
"published_at": "2024-01-15T10:35:00-05:00",
"template_suffix": null,
"published_scope": "web",
"tags": "wallet, leather, accessories, gifts, mens",
"status": "active",
"admin_graphql_api_id": "gid://shopify/Product/7234567890123",
"variants": [
{
"id": 42345678901234,
"product_id": 7234567890123,
"title": "Brown",
"price": "49.99",
"position": 1,
"inventory_policy": "deny",
"compare_at_price": "69.99",
"option1": "Brown",
"option2": null,
"option3": null,
"created_at": "2024-01-15T10:30:00-05:00",
"updated_at": "2024-11-20T14:45:30-05:00",
"taxable": true,
"barcode": "736594012845",
"fulfillment_service": "manual",
"grams": 85,
"inventory_management": "shopify",
"requires_shipping": true,
"sku": "CLW-001-BRN",
"weight": 0.187,
"weight_unit": "lb",
"inventory_item_id": 44567890123456,
"inventory_quantity": 42,
"old_inventory_quantity": 45,
"admin_graphql_api_id": "gid://shopify/ProductVariant/42345678901234",
"image_id": 31234567890123
}
],
"options": [
{
"id": 9123456789012,
"product_id": 7234567890123,
"name": "Color",
"position": 1,
"values": ["Brown", "Black", "Tan"]
}
],
"images": [
{
"id": 31234567890123,
"alt": "Brown leather wallet front view",
"position": 1,
"product_id": 7234567890123,
"created_at": "2024-01-15T10:32:00-05:00",
"updated_at": "2024-01-15T10:32:00-05:00",
"admin_graphql_api_id": "gid://shopify/ProductImage/31234567890123",
"width": 2048,
"height": 2048,
"src": "https://cdn.shopify.com/s/files/1/0612/3456/7890/products/classic-leather-wallet-brown.jpg?v=1705331520",
"variant_ids": [42345678901234]
}
],
"image": {
"id": 31234567890123,
"alt": "Brown leather wallet front view",
"position": 1,
"product_id": 7234567890123,
"created_at": "2024-01-15T10:32:00-05:00",
"updated_at": "2024-01-15T10:32:00-05:00",
"admin_graphql_api_id": "gid://shopify/ProductImage/31234567890123",
"width": 2048,
"height": 2048,
"src": "https://cdn.shopify.com/s/files/1/0612/3456/7890/products/classic-leather-wallet-brown.jpg?v=1705331520",
"variant_ids": [42345678901234]
}
}
Select product collections in Prismic
Follow these steps when content writers need to select an individual product collection from a Shopify store. The collection’s products can be displayed from the website.
Add an integration endpoint to your website
Making product collections available to integration fields requires a custom integration catalog.
To begin, install Shopify’s Storefront API client.
npm install @shopify/storefront-api-client
Next, add an API endpoint that returns your store’s collections.
src/app/api/collections/route.tsimport type { IntegrationAPIItem, IntegrationAPIResults, } from "@prismicio/client"; import { createStorefrontApiClient } from "@shopify/storefront-api-client"; export const dynamic = "force-dynamic"; const MAX_PER_PAGE = 50; const shopify = createStorefrontApiClient({ storeDomain: `https://${process.env.SHOPIFY_STORE_DOMAIN}`, apiVersion: "2023-10", publicAccessToken: process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!, }); export type ShopifyCollection = { id: string; handle: string; title: string; description: string; image?: { url: string; }; }; export async function GET(request: Request) { const { searchParams } = new URL(request.url); const page = parseInt(searchParams.get("page") ?? "1") || 1; const response = await shopify.request( `#graphql query { collections(first: 250) { edges { node { id title description handle updatedAt image { url } } } } } `, ); const collections = response.data?.collections?.edges ?? []; const startIndex = (page - 1) * MAX_PER_PAGE; const endIndex = startIndex + MAX_PER_PAGE; const paginatedCollections = collections.slice(startIndex, endIndex); const results: IntegrationAPIItem<ShopifyCollection>[] = paginatedCollections.map(({ node }) => ({ id: node.id, title: node.title, description: node.description, image_url: node.image?.url, last_update: new Date(node.updatedAt).getTime(), blob: { id: node.id, handle: node.handle, title: node.title, description: node.description, image: node.image, }, })); const response_data: IntegrationAPIResults<ShopifyCollection> = { results_size: collections.length, results, }; return Response.json(response_data); }
Deploy your website
Your API endpoint needs to be deployed and accessible by Prismic.
Follow the deployment instructions for Next.js, Nuxt, or SvelteKit before continuing. Remember to add your environment variables to your deployment.
You’ll use your website’s deployed URL in the next step.
Create an integration catalog
Follow the linked guide to connect the API endpoint to a custom integration catalog.
Learn how to create a custom integration catalog
Use the following field values when creating the catalog:
Field Description Catalog Name ”Product Collections” Description ”Product collections from the Shopify store.” Endpoint The full public URL to the API endpoint (e.g. https://example.com/api/collections
)Access Token An optional secret string used to authenticate API calls. Add a collection field to a content model
After creating the catalog, connect it to an integration field in a slice, page type, or custom type depending on where you need the product data.
Learn how to add an integration field
Display the collection
The integration field provides collection metadata. In some cases, content from the metadata is sufficient.
import { isFilled } from "@prismicio/client"; { isFilled.integration(slice.primary.collection) && ( <div> <h3>{slice.primary.collection.title}</h3> <p>{slice.primary.collection.description}</p> </div> ); }
If you need to fetch the collection’s products, use Shopify’s Storefront API client.
This example shows how to fetch a collection’s products using the Shopify Storefront API client.
src/slices/FeaturedCollection/index.tsximport type { Content } from "@prismicio/client"; import { isFilled } from "@prismicio/client"; import type { SliceComponentProps } from "@prismicio/react"; import { createStorefrontApiClient } from "@shopify/storefront-api-client"; import type { ShopifyCollection } from "@/app/api/collections/route"; const shopify = createStorefrontApiClient({ storeDomain: `https://${process.env.SHOPIFY_STORE_DOMAIN}`, apiVersion: "2023-10", publicAccessToken: process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!, }); type FeaturedCollectionProps = SliceComponentProps<Content.FeaturedCollectionSlice>; // Using the App Router and a React Server Component, this component can fetch // data at render time on the server. export default async function FeaturedCollection({ slice, }: FeaturedCollectionProps) { if (!isFilled.integration(slice.primary.collection)) { return null; } const collection = slice.primary.collection as ShopifyCollection; // Fetch collection with products directly in the component. const response = await shopify.request( `#graphql query ($handle: String!) { collection(handle: $handle) { title description products(first: 10) { edges { node { id title handle priceRange { minVariantPrice { amount currencyCode } } } } } } } `, { variables: { handle: collection.handle, }, }, ); const collection = response.data?.collection; return ( <div> <h2>{collection?.title}</h2> <p>{collection?.description}</p> <div> {collection?.products.edges.map(({ node: product }) => ( <div key={product.id}> <h3>{product.title}</h3> <p> From {product.priceRange.minVariantPrice.currencyCode}{" "} {product.priceRange.minVariantPrice.amount} </p> </div> ))} </div> </div> ); }
Add a collection to a page
Test your new field by selecting a product collection in a page. If everything was set up correctly, you should see the collection displayed on your page.
Product collection metadata
The collection data returned by Prismic’s Content API includes the following fields:
id
string
The collection’s unique identifier from Shopify
handle
string
The collection’s URL handle (used for Storefront API queries)
title
string
description
string
The collection’s description text
image
object
The collection’s image object containing the URL
Here is an example of what an integration field containing a Shopify collection looks like from the Content API:
{
"id": "gid://shopify/Collection/123456789",
"handle": "summer-collection",
"title": "Summer Collection",
"description": "Our latest summer arrivals featuring lightweight fabrics and vibrant colors",
"image": {
"url": "https://cdn.shopify.com/s/files/1/0612/3456/7890/collections/summer-collection-hero.jpg"
}
}