Adding or Removing Line Items from Cart Causes Active Cart Count To Skyrocket with Storefront API

Solved

Adding or Removing Line Items from Cart Causes Active Cart Count To Skyrocket with Storefront API

BrandBuilder
Shopify Partner
20 3 2

Working on a headless implementation on NextJS via Storefront API.

Issue: I have a cart. If I add an item to the cart, the active cart count increases by 1. If I add another item to the cart, we would expect that cart count to stay at 1 (because it's the same cart with different items). However, the count continues to rise. This same thing happens if we remove items from the cart.

For example, 2 items added and 2 items removed causes the Live View dashboard to show 4 total active carts!

Adding / Removing is done via the GraphQL API.

Other facts:
- I create the cart upon initial page load with the cartCreate mutation and store the cart ID in local storage
- Every subsequent operation pulls from local storage so the ID is the same. I know it works because the actual rendered cart look exactly as it should, with quantities and whatnot. (Also verified with console logs)

Any ideas what could be wrong?

Update 1: If you update the cart, this issue happens. Basically any change to the cart causes the active cart count to bump by 1

Accepted Solution (1)

BrandBuilder
Shopify Partner
20 3 2

This is an accepted solution.

Solved. Credit to this Karve Digital Article

It turns out, not mentioned in the docs, you must pass the _shopify_s and _shopify_y cookies along with the cart requests to the storefront API. For example:

// src/actions/cart.ts
// NextJS v15 with TypeScript

import { createStorefrontApiClient } from "@shopify/storefront-api-client";

const client = createStorefrontApiClient({
  storeDomain: "your_url_here",
  apiVersion: "2025-04",
  publicAccessToken: "your_public_access_token_here",
});


// 1. Implement below -- gets the shopify cookies and returns the header string needed in the requests
async function getShopifyCookieHeaders(): Promise<
  { cookie: string } | undefined
> {
  const cookieStore = await cookies();
  const shopifyY = cookieStore.get("_shopify_y")?.value;
  const shopifyS = cookieStore.get("_shopify_s")?.value;

  if (!shopifyY || !shopifyS) {
    return undefined;
  }

  return {
    cookie: `_shopify_y=${shopifyY}; _shopify_s=${shopifyS};`,
  };
}

// Adds an item to cart with mutation akin to what's in the docs. However, note the inclusion of headers in the mutation request.
export async function addToCart(variables: CartLinesAddMutationVariables) {
  const headers = await getShopifyCookieHeaders();

  const response = await client.request<CartLinesAddMutation>(
    cartLinesAddGQLString,
    {
      variables,
      headers,
    }
  );

  return response;
}

 
I kind of think it's crazy how this is mentioned nowhere in the docs. Unless I've just totally missed it.

View solution in original post

Replies 5 (5)

Dotsquares
Shopify Partner
381 22 52

Hi @BrandBuilder,

 

Here are few things that i think of....

 

What You’ve Done Right:

 

  • You’re storing the cart ID in localStorage – good!
  • You’re verifying that it’s being reused – also good.
  • The cart UI is accurate – great, this means your implementation is likely solid.

Workarounds & Best Practices

 

1. Ignore Live View for Cart Metrics in Headless
Live View just isn't reliable for headless cart analytics. It’s built for standard Shopify stores using the default sales channel. Instead:

Use custom analytics with tools like GA4, Segment, Mixpanel, etc.

Track your own cart sessions and active carts.

 

2. Track Carts on Your Backend (optional)
If you need accurate active cart counts:

Create a server endpoint to log cart IDs (or use Shopify’s webhook system with cartCreate)

Log only unique cart IDs within a session timeframe (e.g., 30 mins idle time = expired cart)

 

3. Use cartUpdatedAt to Determine Cart Session
Each cart object has a createdAt and updatedAt timestamp. Use these to filter or determine whether it’s actually an existing session or a new cart.

 

4. Suppress CartCreate on Every Page Load
Make sure you're not creating a new cart on every page load unless needed. If cartCreate is being triggered too early (e.g., SSR or hydration), you might be unintentionally creating new carts before the localStorage ID is read.

 

Debug Tip
Add a logging system like this in dev:

console.log("Cart ID:", localStorage.getItem('cartId'));

 

And ensure:

  • cartCreate is only called if no cart ID exists
  • cartLinesAdd, cartLinesRemove use the same ID

 

Hope this will help and solve the issue. Let me know if you need more help.

 

Regards,

Dotsquares Ltd


Problem Solved? ✔ Accept and Like solution to help future merchants.


Shopify Partner Directory | Trustpilot | Portfolio
BrandBuilder
Shopify Partner
20 3 2

All is good advice -- I have considered just ditching analytics there. I guess honestly as long as FB and/or google have analytics the shopify stuff is kinda useless.

Everything you've said code-wise I've implemented. It's either A) I forgot to implemnet something that's not in the docs cuz I've read through them 10x over, or B) there's a bug. 

I'll reach out to shopify too and may just ditch the analytics for now as you suggested. I wish it just worked as it was supposed to :<

Dotsquares
Shopify Partner
381 22 52

Hi @BrandBuilder ,

 

Let me know if it works. Otherwise, I can look into the issue.

 

Regards,

Dotsquares Ltd


Problem Solved? ✔ Accept and Like solution to help future merchants.


Shopify Partner Directory | Trustpilot | Portfolio
BrandBuilder
Shopify Partner
20 3 2

If you want to look that would be great -- i can send you some stuff if that works.

I also see you're from a dev firm; I don't want to waste your time (I'm not looking to pay for dev work), but if you would still want to look at it I would be very grateful! Please let me know.

BrandBuilder
Shopify Partner
20 3 2

This is an accepted solution.

Solved. Credit to this Karve Digital Article

It turns out, not mentioned in the docs, you must pass the _shopify_s and _shopify_y cookies along with the cart requests to the storefront API. For example:

// src/actions/cart.ts
// NextJS v15 with TypeScript

import { createStorefrontApiClient } from "@shopify/storefront-api-client";

const client = createStorefrontApiClient({
  storeDomain: "your_url_here",
  apiVersion: "2025-04",
  publicAccessToken: "your_public_access_token_here",
});


// 1. Implement below -- gets the shopify cookies and returns the header string needed in the requests
async function getShopifyCookieHeaders(): Promise<
  { cookie: string } | undefined
> {
  const cookieStore = await cookies();
  const shopifyY = cookieStore.get("_shopify_y")?.value;
  const shopifyS = cookieStore.get("_shopify_s")?.value;

  if (!shopifyY || !shopifyS) {
    return undefined;
  }

  return {
    cookie: `_shopify_y=${shopifyY}; _shopify_s=${shopifyS};`,
  };
}

// Adds an item to cart with mutation akin to what's in the docs. However, note the inclusion of headers in the mutation request.
export async function addToCart(variables: CartLinesAddMutationVariables) {
  const headers = await getShopifyCookieHeaders();

  const response = await client.request<CartLinesAddMutation>(
    cartLinesAddGQLString,
    {
      variables,
      headers,
    }
  );

  return response;
}

 
I kind of think it's crazy how this is mentioned nowhere in the docs. Unless I've just totally missed it.