First-Party Domain Config
Getting a custom domain pointing at your sGTM server is the foundation. Making that domain deliver maximum first-party value requires deliberate cookie configuration. This article covers how sGTM sets cookies, what the FPID identifier is, cookie attribute recommendations, and the common misconfigurations that undermine first-party benefits.
How sGTM sets cookies
Section titled “How sGTM sets cookies”Client-side tracking sets cookies via JavaScript: document.cookie = "_ga=..."; Max-Age=63072000". This is the mechanism that Safari’s ITP attacks — JavaScript-set cookies classified as belonging to a tracker are capped at 7 days (or 24 hours if the domain is flagged).
sGTM sets cookies via HTTP response headers:
Set-Cookie: _ga=GA1.1.1234567890.1711900000; Max-Age=63072000; Path=/; Domain=.yoursite.com; Secure; SameSite=NoneHTTP response header cookies from a first-party server are not subject to ITP’s JavaScript cookie cap. A cookie set this way with Max-Age=63072000 (2 years) will persist for 2 years on Safari, Firefox, and Chrome — not 7 days.
This is the fundamental mechanism that makes sGTM’s cookie persistence valuable.
The GA4 cookie and FPID
Section titled “The GA4 cookie and FPID”Two cookies are relevant to GA4 user identification in an sGTM context:
The _ga cookie
Section titled “The _ga cookie”The _ga cookie contains the GA4 client_id — the persistent identifier that GA4 uses to recognize returning users and stitch sessions into user journeys. Without a stable _ga cookie, every Safari user who returns after more than 7 days appears as a new user.
When sGTM’s GA4 client processes an incoming request, it reads the _ga cookie from the request headers. If no _ga cookie exists, it creates a new client_id and sets the _ga cookie in the response.
The key: because this cookie is set via HTTP response headers from collect.yoursite.com, it lives for the full Max-Age you configure — not the 7-day cap that applies to JavaScript-set cookies.
The FPID cookie
Section titled “The FPID cookie”FPID (First-Party ID) is a server-side identifier that sGTM’s GA4 client generates and manages. When FPID is enabled:
- The GA4 client generates a UUID on the user’s first visit and sets it as an HTTP cookie:
FPID=<uuid>; Max-Age=63072000; ... - On subsequent visits, the GA4 client reads the FPID cookie and uses it as the
client_idfor GA4 events - The FPID takes precedence over the
_gacookie when both are present
FPID provides more stable user identification than _ga because it is generated server-side (not susceptible to JavaScript restrictions) and is stored as an HTTP-only cookie (not accessible to browser JavaScript, making it harder for browser extensions to detect and delete).
Configuring cookie attributes
Section titled “Configuring cookie attributes”The GA4 client in sGTM sets _ga and FPID automatically with reasonable defaults. However, you can and should verify the attributes being used.
Recommended cookie attributes
Section titled “Recommended cookie attributes”Set-Cookie: _ga=GA1.1.1234567890.1711900000; Max-Age=63072000; // 2 years Path=/; // Available on all paths Domain=.yoursite.com; // Leading dot: available on all subdomains Secure; // HTTPS only SameSite=None // Required for cross-site use (e.g., iframes)For FPID:
Set-Cookie: FPID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx; Max-Age=63072000; Path=/; Domain=.yoursite.com; Secure; HttpOnly; // Not accessible to JavaScript SameSite=Strict // FPID is a first-party identifier — strict is fineThe Domain attribute
Section titled “The Domain attribute”Setting Domain=.yoursite.com (with leading dot) makes the cookie available on all subdomains: www.yoursite.com, shop.yoursite.com, blog.yoursite.com. Without the leading dot, the cookie is only available on the exact hostname yoursite.com.
For most sites, the leading dot is correct. For organizations with strict subdomain separation or multi-tenant architectures, consider whether cross-subdomain cookie access is appropriate.
The HttpOnly flag
Section titled “The HttpOnly flag”HttpOnly cookies cannot be read by JavaScript. For tracking cookies, this has a nuance: your client-side GA4 tag will not be able to read the FPID value from JavaScript. The sGTM GA4 client reads it from request headers — client-side code never needs it. Set HttpOnly on FPID; it is optional for _ga.
SameSite attribute
Section titled “SameSite attribute”SameSite=None; Secure: Cookie is sent on cross-site requests. Required if your site is embedded in iframes on other domains or if tracking needs to work in third-party contexts. RequiresSecureflag.SameSite=Lax: Cookie is sent on same-site requests and top-level navigations from other sites. Appropriate for most analytics cookies.SameSite=Strict: Cookie is only sent on same-site requests. Too restrictive for most tracking use cases.
For _ga, use SameSite=None; Secure if you need cross-site tracking, or SameSite=Lax otherwise. For FPID, SameSite=Strict is appropriate since it is a pure first-party identifier.
Enabling FPID in sGTM
Section titled “Enabling FPID in sGTM”FPID is enabled through the GA4 client configuration in your sGTM container:
-
In your sGTM container, navigate to Clients
-
Click your GA4 client (the built-in one)
-
Look for the Cookie Name setting — by default it is
_ga -
FPID is handled automatically by the GA4 client when it detects no
_gacookie. To verify FPID is working, check for theFPIDcookie in DevTools → Application → Cookies after a first visit.
If you want to explicitly control FPID behavior, you can do so via a custom variable that reads the x-sst-system-properties event parameter — but this is advanced configuration not needed for most implementations.
Cookie refresh pattern
Section titled “Cookie refresh pattern”On each request, sGTM should refresh the cookie’s expiration date — not just read it. This prevents cookies from expiring on users who visit regularly.
The GA4 client refreshes _ga and FPID on each request by re-setting the cookie in the response headers with the full Max-Age. This is automatic behavior you do not need to configure separately.
Verify the refresh is happening:
- Open DevTools → Application → Cookies
- Note the expiration date of
_gabefore a pageview - Trigger a pageview
- Refresh the cookie list — the expiration should have extended to full duration
If the expiration is not refreshing, your sGTM server may not be setting the cookie in the response (check Preview mode to see if Set-Cookie headers appear in the response).
Privacy and consent compliance
Section titled “Privacy and consent compliance”What changes with server-side cookies: the mechanism, not the obligation. Your consent management platform must still capture and record consent before tracking cookies are set.
In practice, implement consent enforcement at two layers:
Client-side: Your CMP prevents GA4 tags from firing before consent is granted. This prevents the browser from sending requests to your sGTM server.
Server-side: Your sGTM server checks the consent parameters included in incoming requests (typically forwarded by the GA4 client from Consent Mode signals) and does not set tracking cookies if consent has not been granted.
The belt-and-suspenders approach is more defensible from a compliance standpoint than relying on either layer alone.
Verifying first-party cookie behavior
Section titled “Verifying first-party cookie behavior”After setup, verify that cookies are being set with the expected attributes:
# Check cookie attributes using curlcurl -si https://collect.yoursite.com/g/collect \ -d "v=2&tid=G-XXXXXXXX&cid=1234&en=page_view&dl=https%3A%2F%2Fyoursite.com" \ | grep -i "set-cookie"
# Expected output:# Set-Cookie: _ga=GA1.1.1234.1711900000; Max-Age=63072000; Path=/;# Domain=.yoursite.com; Secure; SameSite=None# Set-Cookie: FPID=xxxxxxxx-xxxx-...; Max-Age=63072000; Path=/;# Domain=.yoursite.com; Secure; HttpOnly; SameSite=StrictIn the browser:
- DevTools → Application → Cookies → select
yoursite.com - Find
_gacookie — verify:- Domain:
.yoursite.com - Expires/Max-Age: 400 days or more from today (not 7 days)
- Secure: checked
- Domain:
- Find
FPIDcookie — verify:- HttpOnly: checked
- Expires: 400 days or more
Common mistakes
Section titled “Common mistakes”Not setting Domain with leading dot. Cookie set for collect.yoursite.com without a domain attribute is only available on that exact subdomain, not on www.yoursite.com. Your main site cannot read the cookie. Include Domain=.yoursite.com.
Relying on client-side GA4 to set cookies. If your GA4 tag still sets the _ga cookie via JavaScript (before going through sGTM), the server-set cookie may conflict with the JavaScript-set one. The first one to arrive wins in some cases. Ensure only the server sets _ga in a server-side setup.
Conflating first-party context with consent exemption. First-party server-set cookies for analytics and advertising require consent. Do not confuse the technical architecture with legal obligations.
Inconsistent SameSite settings. If your main site uses SameSite=Strict on session cookies but your tracking cookies use SameSite=None, some security scanners will flag the inconsistency. Align your cookie policy across all cookies.