Skip to main content
Build a single-page ordering storefront using React 19, Vite, and @craveup/storefront-sdk. This guide covers project setup, fetching menus, and managing a cart — all in the browser.

Prerequisites

  • Node.js 18+ and a package manager (pnpm, npm, or yarn)
  • A Crave API key from the Dashboard
  • At least one live location in your merchant account

1. Create a React project

npm create vite@latest my-storefront -- --template react-ts
cd my-storefront

2. Install the SDK

npm install @craveup/storefront-sdk

3. Set environment variables

Create a .env file in the project root:
VITE_CRAVEUP_API_KEY=sk_live_your_api_key
VITE_LOCATION_ID=loc_your_location_id
VITE_LOCATION_SLUG=your-restaurant-slug
Vite exposes variables prefixed with VITE_ to client code via import.meta.env.

4. Create the storefront client

import { createStorefrontClient } from '@craveup/storefront-sdk';

export const storefront = createStorefrontClient({
  apiKey: import.meta.env.VITE_CRAVEUP_API_KEY,
});

5. Fetch and display the menu

import { useEffect, useState } from 'react';
import { storefront } from './lib/storefront';
import type { MerchantApiResponse } from '@craveup/storefront-sdk';

const LOCATION_SLUG = import.meta.env.VITE_LOCATION_SLUG;

function App() {
  const [merchant, setMerchant] = useState<MerchantApiResponse | null>(null);

  useEffect(() => {
    storefront.merchant.getBySlug(LOCATION_SLUG).then(setMerchant);
  }, []);

  if (!merchant) return <p>Loading...</p>;

  return (
    <div style={{ maxWidth: 800, margin: '0 auto', padding: 32 }}>
      <h1>{merchant.name}</h1>
      <p>{merchant.bio}</p>
      <h2>Locations</h2>
      {merchant.locations.map((loc) => (
        <div key={loc.id} style={{ padding: 16, border: '1px solid #ddd', borderRadius: 8, marginTop: 12 }}>
          <strong>{loc.restaurantDisplayName}</strong>
          <p>{loc.addressString}</p>
        </div>
      ))}
    </div>
  );
}

export default App;

6. Add cart functionality

Create a simple hook to manage the ordering session and cart state.
import { useState, useCallback } from 'react';
import { storefront } from '../lib/storefront';
import type { StorefrontCart } from '@craveup/storefront-sdk';

const LOCATION_ID = import.meta.env.VITE_LOCATION_ID;

export function useCart() {
  const [cartId, setCartId] = useState<string | null>(null);
  const [cart, setCart] = useState<StorefrontCart | null>(null);

  const startSession = useCallback(async () => {
    const session = await storefront.orderingSessions.start(LOCATION_ID, {
      marketplaceId: LOCATION_ID,
    });
    if (session.cartId) setCartId(session.cartId);
    return session.cartId;
  }, []);

  const addItem = useCallback(async (productId: string, quantity = 1) => {
    const id = cartId ?? (await startSession());
    if (!id) return;
    const result = await storefront.cart.addItem(LOCATION_ID, id, {
      productId,
      quantity,
      selections: [],
      itemUnavailableAction: 'remove_item',
    });
    setCart(result.cart);
    setCartId(result.cartId);
  }, [cartId, startSession]);

  const refreshCart = useCallback(async () => {
    if (!cartId) return;
    const updated = await storefront.cart.get(LOCATION_ID, cartId);
    setCart(updated);
  }, [cartId]);

  return { cart, cartId, addItem, refreshCart, startSession };
}

7. Run the dev server

pnpm dev
Open the URL shown in the terminal (usually http://localhost:5173).

Next steps