August 4, 20263 min read

Sharing cookies between a headless Shopify storefront and its checkout

Tweek-Eek runs as a headless Shopify store: a Next.js storefront on tweek-eek.com, with the regular Shopify checkout on checkout.tweek-eek.com. Two applications on two hosts, and a visitor who should experience them as one shop.

Cookies do not cross that boundary by themselves. When I built the store I could not find a clear write-up on how to share cookies between the two domains — and how to update them safely — so this is the solution I ended up with.

Cookies are host-only by default

Set a cookie the obvious way on the storefront:

TypeScript
document.cookie = 'cookie_consent=true; Path=/'

and it belongs to tweek-eek.com alone. The browser treats the checkout subdomain as a different host and never sends the cookie there. The visitor accepts cookies on the storefront, clicks through to pay, and the checkout has no idea a choice was ever made. Analytics break the same way: the session is cut in half at the exact step you care about most.

The Domain attribute fixes the sharing part. A cookie set with Domain=.tweek-eek.com is sent to the apex domain and every subdomain under it, including the checkout:

TypeScript
document.cookie = [
  'cookie_consent=true',
  'Domain=.tweek-eek.com',
  'Path=/',
  'Max-Age=31536000',
  'Secure',
  'SameSite=None',
].join('; ')

Or with a helper like cookies-next:

TypeScript
import { setCookie } from 'cookies-next'

setCookie('cookie_consent', 'true', {
  domain: '.tweek-eek.com',
  path: '/',
  maxAge: 60 * 60 * 24 * 365,
  secure: true,
  sameSite: 'none',
})

Three details that matter:

  • SameSite=None requires Secure. The storefront and the checkout technically count as the same site, so Lax survives the redirect to checkout too, but None removes any doubt for requests between the two hosts.
  • The leading dot is optional in modern browsers — Domain=tweek-eek.com behaves identically — but it makes the intent readable.
  • A page can only widen a cookie to a domain its own host belongs to. Both hosts belong to .tweek-eek.com, so both sides can read and rewrite the same cookie.

This is the part I could not find documented anywhere. Writing a cookie with the same name but a different Domain does not update the original — it creates a second cookie. If you started host-only and later switch to Domain=.tweek-eek.com, visitors end up with two cookie_consent cookies, and which one a page reads is effectively undefined.

So always write a shared cookie with exactly the same domain and path, and if an old host-only version can exist, delete it explicitly before writing the new one:

TypeScript
document.cookie = 'cookie_consent=; Path=/; Max-Age=0'

setCookie('cookie_consent', 'false', {
  domain: '.tweek-eek.com',
  path: '/',
  maxAge: 60 * 60 * 24 * 365,
  secure: true,
  sameSite: 'none',
})

Shopify's cookies: don't forge them, request them

Sharing your own cookies is half the story. The checkout does not read cookie_consent — Shopify keeps consent in its own _tracking_consent cookie, a versioned, URL-encoded blob you should not construct by hand. Instead, ask the Storefront API to mint a valid value with the consentManagement query, aimed at the checkout domain:

TypeScript
const query = `query {
  consentManagement {
    cookies(
      visitorConsent: { marketing: true, analytics: true, preferences: true }
      origReferrer: ""
      landingPage: "/"
    ) {
      trackingConsentCookie
      cookieDomain
    }
  }
}`

const res = await fetch('https://checkout.tweek-eek.com/api/unstable/graphql.json', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Shopify-Storefront-Access-Token': storefrontToken,
  },
  body: JSON.stringify({ query }),
})

const json = await res.json()
const consent = json?.data?.consentManagement?.cookies?.trackingConsentCookie

The token here is the public Storefront API token, so it is safe in the browser. The response contains the exact cookie value Shopify expects — cookieDomain even confirms where it should live. Write it to the shared domain and the checkout picks it up as if it had set it itself:

TypeScript
if (consent) {
  setCookie('_tracking_consent', decodeURIComponent(consent), {
    domain: '.tweek-eek.com',
    path: '/',
    maxAge: 60 * 60 * 24 * 365,
    secure: true,
    sameSite: 'none',
  })
}

When the visitor changes their preferences later, run the same query with the new visitorConsent values and overwrite the cookie — same name, same domain, same path. Tracking on the checkout now follows the choice made on the storefront.

Verifying

Open DevTools → Application → Cookies on the storefront: the shared cookies should list .tweek-eek.com in the Domain column. Click through to the checkout and look again — same cookie, same value. Two rows with the same name but different domains means you have hit the update problem above: delete the host-only one.

None of this is exotic, but the pieces are scattered across cookie specs and half-related forum threads. Domain-scoped cookies for sharing, identical attributes for updating, and the Storefront API for anything Shopify itself needs to read.