> ## Documentation Index
> Fetch the complete documentation index at: https://docs.replo.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Share a Cart With Your Shopify Theme

> Keep one Shopify cart as shoppers move between your Shopify theme and your Replo site.

When your Replo site runs on a subdomain of your store's domain (for example `shop.yourbrand.com` next to `yourbrand.com`), shoppers can keep one cart across both. Items added on either site show up on the other, and checkout includes everything.

## Before you begin

* Your project uses [Shopify checkout](https://docs.replo.app/commerce/shopify.md).
* Your Replo site is published on a subdomain of your store's primary domain. If your store is on `yourbrand.com` or `www.yourbrand.com`, publish your site on a domain like `shop.yourbrand.com`. See [Custom Domains](https://docs.replo.app/custom-domains.md).

Your Replo site shares its cart automatically. Your theme needs one script.

## Add the script to your theme

**1. Open your theme code**

In your Shopify admin, go to **Online Store → Themes**. Next to your live
theme, click **⋯ → Edit code**, then open `layout/theme.liquid`.

**2. Paste the script**

Paste this script anywhere inside `theme.liquid`, for example just before `</head>`. Placing it in `theme.liquid` loads it on every page of your store.

```html theme={null}
<script>
  (() => {
    // Runs after your store switches to the shared cart. Reloading works on
    // every theme. To update your theme without a reload, replace the body, e.g.:
    //   const cart = await fetch("/cart.js").then((response) => response.json());
    //   document.querySelector(".cart-count").textContent = cart.item_count;
    const updateCartUI = async () => {
      location.reload();
    };

    const domain = location.hostname.replace(/^www\./, "");
    const sharedCookie = "replo_shared_cart";

    const readCookie = (name) => {
      const entry = document.cookie
        .split("; ")
        .find((cookie) => cookie.startsWith(`${name}=`));
      return entry ? decodeURIComponent(entry.slice(name.length + 1)) : null;
    };
    const writeCookie = (name, value, attributes = "") => {
      document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=2592000; SameSite=Lax; Secure${attributes}`;
    };
    const getCart = () =>
      fetch("/cart.js", { cache: "no-store" }).then((response) =>
        response.json(),
      );

    // Shopify only sets the cart cookie once the visitor has a real cart.
    const shareCart = () => {
      const cart = readCookie("cart");
      if (cart && !readCookie(sharedCookie)) {
        writeCookie(sharedCookie, cart, `; Domain=.${domain}`);
      }
    };

    async function useSharedCart() {
      const sharedCart = readCookie(sharedCookie);
      const themeCart = readCookie("cart");
      if (!sharedCart) {
        shareCart();
        return;
      }
      if (sharedCart === themeCart) {
        return;
      }

      const previousCart = themeCart ? await getCart() : null;
      writeCookie("cart", sharedCart);
      if ((await getCart()).token !== sharedCart) {
        // The shared cart is gone, for example after checkout: share this one instead.
        if (themeCart) {
          writeCookie("cart", themeCart);
        } else {
          document.cookie = "cart=; Path=/; Max-Age=0";
        }
        document.cookie = `${sharedCookie}=; Path=/; Max-Age=0; Domain=.${domain}`;
        shareCart();
        return;
      }

      // Add items one at a time: Shopify rejects a whole batch if any item
      // is unavailable, and that item would be skipped at checkout anyway.
      for (const item of previousCart?.items ?? []) {
        await fetch("/cart/add.js", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            id: item.variant_id,
            quantity: item.quantity,
            properties: item.properties ?? {},
            ...(item.selling_plan_allocation
              ? { selling_plan: item.selling_plan_allocation.selling_plan.id }
              : {}),
          }),
        });
      }
      await updateCartUI();
    }

    // Theme add-to-cart buttons create the cart without a page load.
    window.addEventListener("pagehide", shareCart);
    document.addEventListener("visibilitychange", () => {
      if (document.visibilityState === "hidden") {
        shareCart();
      }
    });
    // The lock keeps two open tabs from merging the same items twice.
    const run = () => useSharedCart();
    (navigator.locks
      ? navigator.locks.request("replo-shared-cart", run)
      : run()
    ).catch((error) => {
      console.error("Replo shared cart failed", error);
    });
  })();
</script>
```

**3. Optional: update your cart without a reload**

By default the script reloads the page once when your store switches to the
shared cart, so your header count and cart drawer show every item. To refresh
your theme's cart in place instead, edit `updateCartUI` at the top of the
script. Fetch `/cart.js` for the current cart, then update your theme's cart
count or drawer the way your theme does after an add to cart.

**4. Save and test**

Click **Save**. Add a product on your store, open your Replo site, and check
that the cart shows the same item. Then add a product on your Replo site, go
back to your store, and check that the cart shows both.

## How it works

Both sites read the same Shopify cart, so you don't need to sync anything after setup:

* **Shopper starts on your store:** the script shares your store's cart with your Replo site.
* **Shopper starts on your Replo site:** your store switches to that cart the first time the shopper visits. If the shopper already had items in your store's cart, the script adds them to the shared cart, then reloads the page once (or runs your `updateCartUI`) so your theme's cart shows every item.
* **After checkout:** the next cart either site creates becomes the shared cart.

## FAQ

> **Does this work if my Replo site is on replosites.com or another domain?**
>
> No. Browsers only share cookies between a domain and its subdomains, so your
> Replo site must be on a subdomain of your store's primary domain.

> **Do I need to change anything for my theme's cart drawer or header?**
>
> No. Your theme reads the cart from Shopify as usual. The script reloads the
> page once when it switches your store to the shared cart, so your header count
> and cart drawer show the right items. To avoid the reload, customize
> `updateCartUI` at the top of the script.

> **What carries over between the two carts?**
>
> Products, quantities, line item properties, and subscription selling plans.
> Cart notes, cart attributes, and discount codes stay with the cart they were
> added to.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.