Server-side GTM first-party and transport URL reference

last verified · against Google server-side Tag Manager documentation as of 2026-07

Server-side GTM first-party transport reference: server_container_url wiring, GA4 client identification, FPID cookies, custom domains, CSP, and self-hosting.

What this is

Server-side Tag Manager routes browser event traffic to a container running on your own infrastructure, where a built-in Google Analytics: GA4 client claims the requests and forwards them to Google. The single wiring point is the web-side Google tag’s server_container_url config option, set to the server container’s Default URL.

Web-side wiring

Item Value Where set
Config option server_container_url gtag.js config / web container Google tag Configuration settings
Value Server container Default URL Copied from the server container
Purpose Redirects GA4 /g/collect-style browser traffic to the server container Single wiring point

The GA4 v2 /g/collect-style requests are redirected to the server container, where the built-in Google Analytics: GA4 client claims and forwards them. In Tag Manager terminology, clients are adapters between the software running on a user’s device and your server container.

GA4 server client identification

Mode Identifier source Cookie Accessibility Lifetime
JavaScript Managed Incoming &cid parameter _ga Browser-readable Subject to browser caps
Server Managed FPID cookie, preferred over incoming &cid FPID HttpOnly (server-only) Extended to ~2 years (practitioner-sourced)
  • The documented GA4 walkthrough sets Cookies and Client Identification to JavaScript Managed.
  • Under Server Managed, the client parses the identifier from the FPID cookie and uses that value to set the Client ID in the outgoing request to Google. Under JavaScript Managed, the client uses the incoming &cid parameter and does not create an FPID cookie.
  • The FPID cookie is written via the Set-Cookie HTTP response header with the HttpOnly flag, so it is not accessible to browser JavaScript — only the web server can read it.
  • If the Name field in the server-managed cookie settings is left blank, the client will not write the FPID cookie and will not read an existing FPID cookie to generate client_id (effectively cookieless).

The ~2-year FPID lifetime, plus its SameSite/Secure attributes, come from practitioner sources (InfoTrust, Simo Ahava), not from an official Google page. Verify the exact default in the GA4 client’s server-managed cookie settings in-product.

GA4 server client activation

Activation option Effect
Default GA4 paths Captures standard GA4 event / collect requests
Default gtag.js paths for specific IDs Serves the gtag.js JavaScript library through your server container URL

The debug view shows an incoming request as collect?v=2&.... The full verbatim list of default request paths the GA4 server client claims (commonly cited as /g/collect, /collect, /gtag/js?id=TAG_ID) is not confirmed word-for-word on an official page; treat the extended list as practitioner-sourced.

Custom-domain hosting options

Option Example Requirement Context
Same-origin (recommended) https://www.example.com/metrics CDN or load balancer to forward requests First-party
Subdomain https://metrics.example.com DNS entry updates First-party
Default *.run.app None Third-party
  • For a true first-party context the tagging server and the website must run on the same domain; only then do you unlock durable cookies and the security benefits.
  • If you use the default *.run.app domain you can only set JavaScript-accessible cookies and lack access to the security and durability benefits of first-party cookies.

Transport methods and required headers

Transport Notes
Image pixel Pixel-based delivery
Fetch API Fetch request
XHR XMLHttpRequest
Service worker in iframe Iframe loaded from your server container domain
Header Directive Must include Reason
Content-Security-Policy img-src [SERVER_CONTAINER_URL] Measurement requests
Content-Security-Policy connect-src [SERVER_CONTAINER_URL] Measurement requests
Content-Security-Policy frame-src [SERVER_CONTAINER_URL] Service-worker iframe transport
X-Frame-Options Must not block iframes from [SERVER_CONTAINER_URL] Service-worker iframe transport

For app / measurement-protocol style requests the pixel URL uses your custom server-container hostname — the Google endpoint hostname is replaced by your server container domain, e.g. https://custom.example.com/app?v=1&tid=TAG_ID&cid=555&t=screenview.

Dependency serving (Google tag gateway)

Item Value
What it does Serves Google scripts such as gtm.js from your first-party infrastructure instead of Google’s servers
Prerequisites Server container + tagging server + configured custom server domain
Serving option 1 CDN (recommended)
Serving option 2 The tagging server itself

Self-hosted (manual) provisioning

Item Value
Docker image gcr.io/cloud-tagging-10302018/gtm-cloud-image:stable
CONTAINER_CONFIG Server container configuration string — required on every instance
RUN_AS_PREVIEW_SERVER=true Marks an instance as a preview server
PREVIEW_SERVER_URL HTTPS URL of the preview server — required on each SST cluster instance
Default port 8080, overridable with the PORT environment variable
Liveness /healthy endpoint — a non-healthy response means restart the server

Both CONTAINER_CONFIG and PREVIEW_SERVER_URL are obtained via Manually provision tagging server in Tag Manager, and every instance must use the same values.

Gotchas

  1. Server-to-server / measurement-protocol requests never appear in the Preview timeline. Cause: a request only shows if it carries the preview cookie or the X-Gtm-Server-Preview header, which non-browser requests lack. Fix: add the X-Gtm-Server-Preview header (copied from the preview mode overlay) to the outbound request. (Header wording is practitioner-sourced; verify against the live debug docs.)
  2. Only the first / config event reaches the server endpoint. Cause: setting the transport on the GA4 config event alone does not reliably propagate to every subsequent event. Fix: set server_container_url on the Google tag / all events, then verify each event’s destination in preview.
  3. GA4 / _ga cookies reset roughly every 7 days for Safari, and returning users are counted as new. Cause: the default *.run.app (third-party) domain or JavaScript-managed cookies are JavaScript-set and hit ITP’s ~7-day cap. Fix: map a first-party custom domain and use Server Managed (FPID, HttpOnly) identification.
  4. FPID / server-managed identification misbehaves with multiple GA trackers or across domains. Cause: FPID is single-cookie oriented and was not designed for multiple trackers or cross-domain use. Fix: use one GA4 client identity per FPID cookie; for cross-domain use the GA linker / FPLC mechanism rather than FPID alone.
  5. Measurement requests to a same-origin path (e.g. /metrics) return 404 or never reach the tagging server. Cause: same-origin hosting needs a CDN or load balancer rule to forward that path. Fix: configure the CDN / load balancer to route the chosen path prefix to the tagging server.
  6. The browser blocks the service-worker/iframe transport or measurement fetch requests. Cause: CSP or X-Frame-Options on the main site does not allow the server container URL. Fix: add [SERVER_CONTAINER_URL] to img-src, connect-src, and frame-src, and ensure X-Frame-Options does not block iframes from it.

Quick recipes

Wire the web tag to the server container:

gtag-server-config.js
// Web container Google tag / gtag.js config option
gtag('config', 'G-XXXXXXX', {
server_container_url: 'https://metrics.example.com'
});

Allow the server container in your Content Security Policy:

csp-header.txt
Content-Security-Policy:
img-src 'self' https://metrics.example.com;
connect-src 'self' https://metrics.example.com;
frame-src 'self' https://metrics.example.com

Run a self-hosted tagging server (main instance):

run-tagging-server.sh
docker run -p 8080:8080 \
-e CONTAINER_CONFIG='<config string from Tag Manager>' \
-e PREVIEW_SERVER_URL='https://preview.example.com' \
gcr.io/cloud-tagging-10302018/gtm-cloud-image:stable

Run the companion preview server:

run-preview-server.sh
docker run -p 8080:8080 \
-e CONTAINER_CONFIG='<config string from Tag Manager>' \
-e RUN_AS_PREVIEW_SERVER=true \
gcr.io/cloud-tagging-10302018/gtm-cloud-image:stable

Check liveness:

healthcheck.sh
curl -f https://metrics.example.com/healthy || echo "restart the server"

Route a measurement-protocol request through the debug session:

preview-mp.sh
curl "https://custom.example.com/app?v=1&tid=TAG_ID&cid=555&t=screenview" \
-H "X-Gtm-Server-Preview: <token from the preview mode overlay>"

Sources

Official pages these values were read from (read 2026-07-20):

FPID behaviour, the ~2-year lifetime, and the X-Gtm-Server-Preview header wording are corroborated by practitioner sources rather than an official Google page, and are flagged above for in-product verification:

Two things the docs do not settle, flagged rather than guessed: the tagging server’s CORS header behaviour for cross-origin fetch/XHR transport is not spelled out on the official pages (the docs address it indirectly via the same-origin recommendation and the connect-src requirement), and Consent Mode interaction with the server_container_url wiring — whether consent state is forwarded and how it gates FPID writing — is not detailed; confirm both against the relevant product documentation before relying on them.

Changelog

  • — Initial version, verified against official documentation.

dataLayer

0 events · 0 sent

    • home /
      writing /writing
      guides /guides
      work /#work
      about /about
      colophon /colophon
      toggle analyst mode ctrl+.
      print session receipt /#receipt