Blog

Server-side cookies: SameSite, Secure, and Path settings that work

Three flags determine whether your cookie survives ITP, third-party blocking, and the next browser update.

When you set a cookie from your sGTM container, three flags determine whether the cookie actually does what you want. The defaults in most code samples online are out of date and will silently fail in modern browsers.

SameSite

Three values: Strict, Lax, None. The right answer for analytics cookies is almost always Lax.

  • Strict: cookie sent only when the request originates from the same site. Breaks any cross-domain navigation, including coming from a search engine. Almost never the right choice for analytics.
  • Lax: cookie sent on top-level navigations and same-site requests. The default for most modern browsers if you do not set the flag explicitly. The safe choice.
  • None: cookie sent on every request including third-party. Requires the Secure flag. Only use when you genuinely need the cookie in a third-party context, like an embedded widget on a different domain.

Secure

Always true. The only reason to set it false is if your site has a non-HTTPS section, which is itself a problem worth fixing. Browsers increasingly refuse to set non-Secure cookies on HTTPS responses anyway, so the flag is only honoured when present.

Path

Default is the path the response was served from, which is rarely what you want. For analytics cookies, set Path to / so the cookie is sent on every request to your domain.

If you genuinely want to scope the cookie to a subset of your site (for instance a checkout-only cookie), use a more specific path. But this is rare and usually a sign of over-engineering.

Domain

Not one of the three above, but worth mentioning. Setting Domain to auto lets the cookie be read across subdomains of your site. Setting it to a specific subdomain restricts the cookie to that subdomain only.

For first-party identity cookies that need to be readable from both www.example.com and your tagging subdomain (data.example.com), set Domain to .example.com with the leading dot.

A working baseline

setCookie('_user_id', userId, {
  domain: 'auto',
  path: '/',
  'max-age': 60 * 60 * 24 * 365 * 2,
  secure: true,
  sameSite: 'lax',
  httpOnly: true
});

Two-year max-age, lax SameSite, secure, HttpOnly when you do not need to read it from the browser. This combination survives ITP, third-party blocking, and gives you the longest realistic persistence the browser will honour. The HttpOnly trade-offs are documented separately.