Skip to content

Cross-subdomain tracking

Many real sites span multiple hosts. The marketing pages live on www.example.com. The product app is app.example.com. Checkout is checkout.example.com. A user clicks an ad, lands on www, browses, signs up on app, pays on checkout. The click identifier needs to be readable from all three.

Trackbridge handles this with one config field — cookieDomain — and a handful of things to be aware of.

Set cookieDomain to a parent domain shared by all the hosts you need:

import { createBrowserTracker } from '@trackbridge/browser';
export const tracker = createBrowserTracker({
adsConversionId: process.env.NEXT_PUBLIC_GOOGLE_ADS_CONVERSION_ID!,
ga4MeasurementId: process.env.NEXT_PUBLIC_GA4_MEASUREMENT_ID!,
consentMode: 'v2',
cookieDomain: '.example.com', // ← the change
});

The leading . is conventional but not strictly required by browsers — both .example.com and example.com produce the same effect (a host-prefix-matching cookie). Pick one and use it consistently.

The cookies the SDK writes now include Domain=.example.com:

_tb_gclid=Cj0KCQ...; Domain=.example.com; Secure; SameSite=Lax; Path=/; Expires=<+90d>

Browsers send these cookies on requests to www.example.com, app.example.com, checkout.example.com, and any other subdomain.

The same cookieDomain must be passed to every createBrowserTracker instance across all your apps. If www writes Domain=.example.com and app writes Domain=app.example.com (because someone forgot the config), you end up with two separate cookies — app won’t read what www wrote.

The simplest discipline: make cookieDomain an environment variable (PUBLIC_TRACKBRIDGE_COOKIE_DOMAIN=.example.com), set it in every deployment, and pass it through. One source of truth across all your front-ends.

If www and app are deployed as a single SPA (a Next.js app handling both / and /app/..., for example), this is mostly a non-issue — the cookie is set once and the same browser context reads it on every navigation. cookieDomain is only needed when the user crosses a real host boundary (full-page navigation to a different subdomain).

For full cross-host navigations:

  • The browser sends the existing cookie automatically with the request to the new host.
  • The new host’s createBrowserTracker reads the cookie at init via document.cookie.
  • tracker.getClickIdentifiers() returns the captured value.

No extra forwarding code needed.

If your “subdomains” are actually paths on a reverse-proxy fronted by one host (example.com/marketing/, example.com/app/, example.com/checkout/), cookieDomain doesn’t help — and isn’t needed. A normal host-only cookie works because the host doesn’t change. Skip the config entirely.

Setting cookieDomain only adds the Domain= attribute. The other attributes are unchanged:

  • Secure — still required, still always set. HTTPS only.
  • SameSite=Lax — sent on top-level navigations between subdomains, not on cross-site iframe loads.
  • Path=/ — available across the whole host.
  • Expires — still 90 days by default.

If your apex domain (example.com) also serves user traffic, it’s covered by Domain=.example.com (the leading-dot form makes the cookie available on the apex and any subdomain).

If Domain=example.com (no leading dot) is set, modern browsers behave the same way — the differentiation between Domain=.example.com and Domain=example.com was deprecated.

  • You cannot share cookies across two completely different domains (example.com and another-site.com). Browsers refuse on principle. If you need cross-domain attribution, that’s a different problem (Google’s “linker” parameter is the standard answer; Trackbridge does not implement it).
  • You cannot set Domain= to a public suffix (Domain=.com, Domain=.co.uk). Browsers reject those values. Use your registrable domain.
  • You cannot read the cookie from a host outside the configured domain. A cookie with Domain=.example.com is invisible to unrelated.com.

Same recipe as the consent test, but across hosts:

  1. Open https://www.example.com/?gclid=test123 in a fresh incognito window.
  2. Grant consent (if your tracker uses Consent Mode v2).
  3. DevTools → Application → Cookies. Confirm _tb_gclid=test123 exists with Domain=.example.com.
  4. Navigate to https://app.example.com/.
  5. Open the console and run document.cookie. Confirm _tb_gclid=test123 is in the output.
  6. Confirm tracker.getClickIdentifiers() returns { gclid: 'test123' } on the new host.

If step 5 fails, the Domain= attribute is wrong (or not set) on the original cookie.