> Site index: https://usehardal.com/llms.txt
> Every content route also serves markdown at <url>.md

# GA4 Server-Side Tracking: How It Works and How to Set It Up

Set up GA4 server-side tracking with a server GTM container or the Measurement Protocol. What changes, what stays the same, setup steps, and how to verify it.

Source: https://usehardal.com/ga4-server-side-tracking
Published: 2026-09-26
Updated: 2026-09-26
Author: Ecem Bircan
Category: Google Analytics 4

---

> **Quick answer:** GA4 server-side tracking sends Google Analytics 4 events through a server you control before they reach Google. The common setup keeps the Google tag in the browser but points it at a Google Tag Manager server container on your own subdomain. Your backend can also send events directly with the GA4 Measurement Protocol.

## How GA4 server-side tracking works

By default, the Google tag in the browser sends each GA4 event straight to Google:

```text
Browser -> google-analytics.com -> GA4
```

With server-side tracking, the Google tag sends the same request to a subdomain of your site instead. A Google Tag Manager server container behind that subdomain receives it, processes it, and forwards it to GA4:

```text
Browser -> metrics.example.com -> GTM server container -> GA4
```

Inside the server container, the built-in **Google Analytics client** claims incoming GA4 requests and turns them into event data. A server-side **Google Analytics: GA4** tag forwards that event data to your property. Between the two, you can inspect, change, or drop any parameter.

The browser still decides which events exist and what the page measures. The server decides where those events go and which fields they carry.

## What changes when GA4 goes server-side

| | Client-side GA4 | Server-side GA4 |
|---|---|---|
| Collection endpoint | Google's domain | Your first-party subdomain |
| Blocked by privacy lists | Often | Less often |
| Client ID cookie | `_ga`, set with JavaScript | `_ga`, or a server-managed `FPID` cookie set in an HTTP response |
| Cookie lifetime in Safari | Capped at seven days | Standard HTTP cookie rules when served from your own infrastructure |
| Parameters Google receives | Everything the tag sends | Only what the server tag forwards |
| IP address | Sent to Google | You can drop or truncate it before forwarding |
| Other destinations | Separate browser tags | The same event can feed other server tags |

What does not change: your event names, triggers, and measurement plan; the consent choice collected by your consent management platform; and GA4's own processing, attribution, and thresholds once the data arrives.

## Three ways to run GA4 server-side

### 1. Server-side Google Tag Manager

This is the most common route. The browser keeps the Google tag, and a server container on your domain forwards events to GA4 and any other destination. It suits teams that already run GTM and want page views and interactions to go through a first-party endpoint.

### 2. GA4 Measurement Protocol

Your backend sends events to GA4 over HTTP, with no browser involved:

```text
POST https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXX&api_secret=YOUR_SECRET
```

```json
{
  "client_id": "123456789.1700000000",
  "events": [
    {
      "name": "purchase",
      "params": {
        "session_id": "1700000123",
        "transaction_id": "T-10293",
        "currency": "EUR",
        "value": 129.9
      }
    }
  ]
}
```

Use it for events the browser never sees: completed orders confirmed by a payment provider, refunds, subscription renewals, and offline conversions. Create the API secret in GA4 under **Admin > Data streams > your stream > Measurement Protocol API secrets**.

Two rules keep these events useful. Send the `client_id` from the visitor's `_ga` cookie so GA4 ties the event to the right user, and send `session_id` so it joins a session instead of arriving unattributed. Test payloads against `/debug/mp/collect` first, because the production endpoint accepts malformed events without reporting an error.

### 3. A first-party data platform

A platform such as Hardal collects events once on your first-party endpoint, then forwards them to GA4 alongside Meta, TikTok, Google Ads, and your warehouse. You skip running the container and maintaining each vendor tag. See [what server-side tracking is](https://usehardal.com/server-side-tracking) for how the approaches compare.

## How to set up GA4 server-side tracking with server GTM

### 1. Create the server container

In Google Tag Manager, create a new container and choose **Server** as the target platform. GTM gives you a container config string for the deployment.

### 2. Deploy the container

Run the container on Google Cloud Run, another cloud, or a managed host. For production, run more than one instance so a single failure does not drop events. [Server-side hosting](https://usehardal.com/server-side-hosting) is Hardal's managed option.

### 3. Map a first-party subdomain

Point a subdomain such as `metrics.example.com` at the container and serve it over HTTPS. Serve it from infrastructure your site controls where possible. Safari caps cookies from endpoints it identifies as third-party infrastructure behind a CNAME or a mismatched IP address. The [Safari ITP guide](https://usehardal.com/safari-itp-guide) explains the rules.

### 4. Configure the Google Analytics client

Open **Clients** in the server container. The Google Analytics client is there by default and claims requests on GA4 paths such as `/g/collect`. Under cookie settings, choose between the JavaScript-managed `_ga` cookie and a server-managed `FPID` cookie. The server-managed cookie is set in an HTTP response, which is what gives it a longer life in Safari.

### 5. Add the GA4 tag

Create a **Google Analytics: GA4** tag in the server container. It inherits the measurement ID and parameters from the incoming request. Add a trigger where **Client Name** equals your Google Analytics client, so only GA4 requests fire it.

### 6. Point the web container at the server

In your web container, open the Google tag and add a configuration parameter:

```text
server_container_url = https://metrics.example.com
```

If you are migrating a live property, do not change the production tag yet. Copy it, point the copy at a separate test property, and compare both. The [GA4 dual-tagging guide](https://usehardal.com/server-side-parallel-measurement) covers that migration step by step.

### 7. Verify the full path

Open Preview mode in both containers and load your site in a private window. Check that:

1. The Google tag fires in the web container.
2. The browser's network tab shows the request going to your subdomain, not `google-analytics.com`.
3. The server container's Preview shows the request claimed by the Google Analytics client.
4. The GA4 tag fires once.
5. The event appears in GA4 DebugView.

Repeat with consent denied. The server should still receive the request, and GA4 should get a cookieless ping, not a full event with identifiers. [Cookieless GA4 with server GTM](https://usehardal.com/server-gtm-cookieless-ga4) explains the consent side.

### 8. Publish

Publish the server container first, then the web container.

## Common GA4 server-side problems

- **Double page views.** A `page_view` from the Google tag plus one from an event tag. Each property should get one page view per page load.
- **Events arrive without a session.** Usually Measurement Protocol events sent without `session_id`, or with a `client_id` that does not match the browser's cookie.
- **Consent ignored.** The web container must pass the consent state with each request. The server cannot infer it.
- **Requests still going to Google.** The Google tag is missing `server_container_url`, or another hard-coded gtag snippet on the page bypasses GTM.
- **Short-lived client IDs in Safari.** The subdomain resolves to third-party infrastructure, or the client still uses the JavaScript-managed cookie.
- **Duplicate purchases.** The browser and the backend both send the same purchase to one property. Pick one source per event, or deduplicate on `transaction_id`.
- **Rising hosting bills.** Request volume drives the cost of a self-hosted container. See [how to cut server-side tagging costs](https://usehardal.com/optimizing-server-side-tagging-costs).

## Run GA4 server-side with Hardal

Hardal gives you two ways to move GA4 server-side. Use Hardal's first-party endpoint to send events to GA4 through the Measurement Protocol and route the same events to unlimited destinations, with analytics included. Or run your own server GTM container on Hardal-managed hosting in the US, UK, EU, EMEA, or Asia.

Keep your current GA4 setup live while Hardal runs beside it. Compare the data, fix any gaps, and switch only when the server-side path is ready. Plans start at $249 per month for 5M events. [See pricing](https://usehardal.com/pricing) or [book a demo with the team](https://usehardal.com/contact/demo).

## References

- [Google: Configure the GA4 data stream with server-side tagging](https://developers.google.com/tag-platform/learn/sst-fundamentals/5-sst-setup-analytics)
- [Google: Send data to server-side Tag Manager](https://developers.google.com/tag-platform/tag-manager/server-side/send-data)
- [Google: Preview and debug server-side containers](https://developers.google.com/tag-platform/tag-manager/server-side/debug)
- [Google: GA4 Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/ga4)
