Skip to main content

Quick Start

In this tutorial, you'll build a product listing page that fetches and displays products from your Elastic Path catalog.

What you'll build

A simple product listing that:

  • Fetches products from your catalog
  • Displays product images, names, and prices
  • Handles loading and error states

Prerequisites

  • Node.js 18+ and npm installed
  • An Elastic Path store with:
    • Published catalog with products
    • API credentials

Step 1: Create a Next.js project

This quickstart uses Next.js, but the SDK works with any JavaScript framework.

npx create-next-app@latest my-elastic-path-store
cd my-elastic-path-store

When prompted, choose:

  • TypeScript: Yes
  • ESLint: Yes
  • Tailwind CSS: Yes (for styling)
  • App Router: Yes

Step 2: Install the SDK

Install the Elastic Path Shopper SDK:

npm install @epcc-sdk/sdks-shopper

Step 3: Set up authentication

Create a .env.local file in your project root:

# Choose your region:
# US East: https://useast.api.elasticpath.com
# EU West: https://euwest.api.elasticpath.com
NEXT_PUBLIC_EPCC_ENDPOINT_URL=https://useast.api.elasticpath.com
NEXT_PUBLIC_EPCC_CLIENT_ID=your-client-id

Step 4: Create the SDK client

Create a new file lib/epcc-client.ts:

// lib/epcc-client.ts
import { configureClient } from "@epcc-sdk/sdks-shopper";

const endpointUrl = process.env.NEXT_PUBLIC_EPCC_ENDPOINT_URL;
const clientId = process.env.NEXT_PUBLIC_EPCC_CLIENT_ID;

if (!endpointUrl || !clientId) {
throw new Error('Missing Elastic Path credentials');
}

// Configure the SDK client
export const client = configureClient(
{
baseUrl: endpointUrl
},
{
clientId,
storage: "localStorage"
}
);

Step 5: Create the products page

Replace the contents of app/page.tsx:

// app/page.tsx
import { getByContextAllProducts } from "@epcc-sdk/sdks-shopper";
import "@/lib/epcc-client"; // Initialize the client

async function getProducts() {
const response = await getByContextAllProducts({
query: {
"page[limit]": 12,
include: ["main_image"]
}
});

return {
products: response.data?.data || [],
mainImages: response.data?.included?.main_images || []
};
}

Add the display logic to the same file:

// app/page.tsx
import Image from "next/image";
import { extractProductImage } from "@epcc-sdk/sdks-shopper";

export default async function ProductsPage() {
const { products, mainImages } = await getProducts();

return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-8">Products</h1>

<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-6">
{products.map((product) => {
const mainImage = extractProductImage(product, mainImages);
const imageUrl = mainImage?.link?.href || "/placeholder.jpg";

return (
<div key={product.id} className="border rounded-lg p-4">
<div className="relative h-48 mb-4">
<Image
src={imageUrl}
alt={product.attributes.name}
fill
className="object-contain"
/>
</div>

<h3 className="font-semibold">
{product.attributes.name}
</h3>

<p className="text-gray-600">
{product.meta?.display_price?.without_tax?.formatted}
</p>
</div>
);
})}
</div>

{products.length === 0 && (
<p className="text-center text-gray-500">No products found</p>
)}
</div>
);
}

Step 6: Complete example

Here's the complete page component:

// app/page.tsx
import { getByContextAllProducts, extractProductImage } from "@epcc-sdk/sdks-shopper";
import "@/lib/epcc-client"; // Initialize the client
import Image from "next/image";

async function getProducts() {
const response = await getByContextAllProducts({
query: {
"page[limit]": 12,
include: ["main_image"]
}
});

return {
products: response.data?.data || [],
mainImages: response.data?.included?.main_images || []
};
}

export default async function ProductsPage() {
try {
const { products, mainImages } = await getProducts();

return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-8">Products</h1>

<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-6">
{products.map((product) => {
const mainImage = extractProductImage(product, mainImages);
const imageUrl = mainImage?.link?.href || "/placeholder.jpg";

return (
<div key={product.id} className="border rounded-lg p-4">
<div className="relative h-48 mb-4">
<Image
src={imageUrl}
alt={product.attributes.name}
fill
className="object-contain"
/>
</div>

<h3 className="font-semibold">
{product.attributes.name}
</h3>

<p className="text-gray-600">
{product.meta?.display_price?.without_tax?.formatted}
</p>
</div>
);
})}
</div>

{products.length === 0 && (
<p className="text-center text-gray-500">No products found</p>
)}
</div>
);
} catch (error) {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-4">Products</h1>
<p className="text-red-500">Failed to load products. Please try again.</p>
</div>
);
}
}

Step 7: Run the application

  1. Start your development server:

    npm run dev
  2. Open your browser and navigate to http://localhost:3000

  3. You should see:

    • A grid of products from your catalog
    • Product images, names, and prices
    • Proper error handling if the API fails

What you've built

✅ A working product listing page
✅ Integration with Elastic Path Catalog API
✅ Proper TypeScript types from the SDK
✅ Error handling and loading states
✅ Responsive grid layout

Next Steps

Now that you have a basic product listing, enhance it with:

FeatureGuide
Pagination and filteringList Products
Product detail pagesGet Product Details
Product variationsVariations Overview
Bundle productsBundles Overview

Resources