Blog

Add a custom hostname header to forwarded requests

When your tagging server proxies to an upstream, the upstream often needs to know the original hostname.

When your sGTM container forwards a request to an upstream service (analytics, webhook, internal API), the upstream sees the request coming from your tagging server's IP, not the original visitor's. Some upstreams need to know the original hostname for routing, logging, or rate limiting. Pass it as a custom header.

The standard headers to forward

HeaderWhat it carries
X-Forwarded-HostOriginal Host header from the browser.
X-Forwarded-ForOriginal client IP (if you forward IP).
X-Forwarded-Protohttps or http.
X-Original-User-AgentOriginal UA, in case the upstream replaces it.
X-Real-IPSome legacy proxies prefer this name.

Forwarding in a Custom Tag

const originalHost = getRequestHeader('host');
const originalIP = getRequestHeader('x-forwarded-for');
const originalUA = getRequestHeader('user-agent');

sendHttpRequest('https://upstream.internal/ingest', {
  method: 'POST',
  body: getRequestBody(),
  headers: {
    'Content-Type': 'application/json',
    'X-Forwarded-Host': originalHost,
    'X-Forwarded-For': originalIP,
    'X-Original-User-Agent': originalUA
  }
});

When the upstream rewrites Host

Some destinations (especially internal services behind a load balancer) rewrite the Host header when receiving a request. If your upstream service uses Host-based routing, you must use a custom header instead of relying on Host. X-Forwarded-Host is the conventional name.

Privacy considerations

If your upstream is third-party (a vendor's API, not your own), think about whether you really want to forward the original IP. Most ad platforms accept it (Meta CAPI uses it for matching), but for non-essential destinations, anonymise or strip it before forwarding.

Verify the upstream sees what you sent

If the upstream is your own service, log the incoming headers for the first few requests after deploying the change. Confirm X-Forwarded-Host matches what you expect. The most common bug is that GTM strips or renames headers automatically; the actual values that arrive at the upstream are sometimes not what your template specified.