Implementing Shopify Cart API

Practical guide to Storefront API mutations and state management

Shopify Storefront APICart APIGraphQLReactImplementation
5 min read

Operating Cart with Shopify Storefront API

To implement Ajax cart, you'll use Shopify Storefront API's "Cart" functionality. This page explains how to call the API and integrate it with frontend state management.

Key API Mutations

Shopify Storefront API is GraphQL-based. For cart operations, you'll use these "mutations":

cartCreate
PurposeCreate a new cart
cartLinesAdd
PurposeAdd items to cart
cartLinesUpdate
PurposeChange item quantities
cartLinesRemove
PurposeRemove items from cart
cartQuery
PurposeFetch cart contents

Overall Flow

The basic cart operation flow looks like this:

First Visit
User arrives at site
Access
Create cart with cartCreate
New cart
Save cart ID to localStorage
Persist
Set cart info to React State
State management
Adding Items
Click Add to Cart
User action
Optimistically update React State
Immediate UI
Execute cartLinesAdd mutation
API call
Result processing
Check API response
Success
Confirm state
Failure
Revert state, show error
Return Visit
User arrives at site
Access
Get cart ID from localStorage
Restore
Restore cart contents with cartQuery
Fetch data
Set to React State
Display

Creating Cart (cartCreate)

When a customer first visits, no cart exists yet. Create one on first item add or initial visit.

mutation cartCreate($input: CartInput!) {
  cartCreate(input: $input) {
    cart {
      id
      checkoutUrl
      lines(first: 100) {
        edges {
          node {
            id
            quantity
            merchandise {
              ... on ProductVariant {
                id
                title
                price {
                  amount
                  currencyCode
                }
              }
            }
          }
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

Key points:

  • cart.id is needed for all subsequent operations
  • checkoutUrl is used when proceeding to purchase
  • Check userErrors for errors

Adding Items (cartLinesAdd)

Use cartLinesAdd to add items to cart.

mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
  cartLinesAdd(cartId: $cartId, lines: $lines) {
    cart {
      id
      lines(first: 100) {
        edges {
          node {
            id
            quantity
            merchandise {
              ... on ProductVariant {
                id
                title
              }
            }
          }
        }
      }
      cost {
        totalAmount {
          amount
          currencyCode
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

Example variables:

{
  "cartId": "gid://shopify/Cart/abc123",
  "lines": [
    {
      "merchandiseId": "gid://shopify/ProductVariant/12345",
      "quantity": 1
    }
  ]
}

Changing Quantities (cartLinesUpdate)

Use cartLinesUpdate to change item quantities.

mutation cartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
  cartLinesUpdate(cartId: $cartId, lines: $lines) {
    cart {
      id
      lines(first: 100) {
        edges {
          node {
            id
            quantity
          }
        }
      }
      cost {
        totalAmount {
          amount
          currencyCode
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

Key point:

  • lines[].id takes the cart line ID (not the product variant ID)
  • Use the node.id returned from cartLinesAdd

Removing Items (cartLinesRemove)

Use cartLinesRemove to delete items from cart.

mutation cartLinesRemove($cartId: ID!, $lineIds: [ID!]!) {
  cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
    cart {
      id
      lines(first: 100) {
        edges {
          node {
            id
            quantity
          }
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

Frontend State Management

Beyond calling APIs, you need to manage cart state on the frontend.

Using React Context

React Context is common for sharing cart state app-wide.

// Cart state
interface CartState {
  cartId: string | null;
  lines: CartLine[];
  totalAmount: string;
  checkoutUrl: string;
  isLoading: boolean;
}

// Cart actions
interface CartActions {
  addToCart: (variantId: string, quantity: number) => Promise<void>;
  updateQuantity: (lineId: string, quantity: number) => Promise<void>;
  removeFromCart: (lineId: string) => Promise<void>;
}

Using Zustand

The lighter state management library "Zustand" is another option. Less boilerplate, simpler to write.

Either choice works—what matters is consistent cart state across the app.

Implementing Optimistic UI

From button click to API response takes 0.2-0.3 seconds. If nothing changes during this time, users feel uncertain.

Optimistic UI updates the UI immediately while sending the API request.

async function addToCart(variantId: string, quantity: number) {
  // 1. Update UI immediately (optimistic)
  setCart(prev => ({
    ...prev,
    lines: [...prev.lines, { variantId, quantity, pending: true }]
  }));

  try {
    // 2. Call API
    const result = await cartLinesAdd(cartId, variantId, quantity);

    // 3. On success, replace with real data
    setCart(prev => ({
      ...prev,
      lines: result.cart.lines,
      totalAmount: result.cart.cost.totalAmount.amount
    }));
  } catch (error) {
    // 4. On failure, revert
    setCart(prev => ({
      ...prev,
      lines: prev.lines.filter(line => !line.pending)
    }));
    showError("Couldn't add to cart");
  }
}

Persisting Cart ID

Save the cart ID to localStorage so cart contents survive page reloads.

// After cart creation
localStorage.setItem('shopify_cart_id', cart.id);

// On return visit
const savedCartId = localStorage.getItem('shopify_cart_id');
if (savedCartId) {
  const cart = await fetchCart(savedCartId);
  setCart(cart);
}

Note:

  • Carts have expiration (typically 10 days on Shopify)
  • Expired cart IDs cause errors—fall back to creating new cart

Error Handling

Consider cases where API calls fail.

Common Errors

Out of stock
CauseItem sold out
SolutionNotify user, offer back-in-stock alert
Cart expired
CauseSaved cart ID invalid
SolutionCreate new cart
Network error
CauseConnection dropped
SolutionRetry, offline handling

Architecture Diagram

The final system architecture looks like this:

Ajax Cart System Architecture
Frontend (Next.js)

Cart UI (Button, Mini cart, Slide) + State Mgmt (Context/Zustand) + localStorage (cart ID storage)

GraphQL
Shopify Storefront API

cartCreate / cartLinesAdd / cartLinesUpdate / cartLinesRemove

Checkout
Shopify Checkout

Navigate via checkoutUrl, payment

Summary

Ajax cart with Shopify Storefront API can be implemented by covering these points:

  1. cartCreate to create cart and save ID
  2. cartLinesAdd/Update/Remove for cart operations
  3. React Context/Zustand for global state management
  4. Optimistic UI for perceived speed improvement
  5. Error handling for robustness

Combining these delivers a smooth shopping experience without page transitions.

Related Topics