PERFMETRIX — in data we trust
All articles
GA413 August 2026·8 min read

GA4 Measurement Protocol: what it can and can't do

It adds events to a session it cannot create. Without a client_id and session_id from a real online visit, your server events land as (not set) / (not set).

DeBy Denis · Perfmetrix

Short answer: the Measurement Protocol adds events to a user Google already knows about. It will not start a session, will not attribute a traffic source on its own, and is not a route around ad blockers or consent. Google states the position directly: "The intent of the Measurement Protocol is to augment automatic collection through gtag, Tag Manager, and Google Analytics for Firebase, not to replace it", and "you must use tagging (gTag, Tag Manager, or Google Analytics for Firebase) to use this protocol" (Google for Developers, checked 13 August 2026). Everything useful it does depends on a client_id, and usually a session_id, lifted from a real browser visit. Send events without them and they arrive, count, and tell you nothing about where they came from.

It attaches events to a session it has no power to create

The single most common disappointment with the Measurement Protocol is watching perfectly valid events pile up under "(not set) / (not set)".

Google's help page names both the symptom and the fix: when session-based Measurement Protocol events are reported as "(not set) / (not set)", you should send the session_id parameter "with a valid value from the client-side event", which "connects Measurement Protocol data with previous session attribution data collected by Google Analytics tags (gtag, GTM, Firebase SDK)" (Analytics Help, checked 13 August 2026).

Read the mechanism in that sentence. The attribution isn't computed from your server request. It already exists, attached to a session the browser created, and your session_id is the join key that reaches it. Google's use-case documentation states the outcome plainly: events meeting the requirements "appear in reports with the same session attributes (such as geographic information, source, medium, and campaign) as online events from the same session" (Google for Developers, checked 13 August 2026). Same attributes as the online session, because they are the online session's attributes.

Which is why the fantasy version of the Measurement Protocol doesn't work. You cannot mint a client_id, POST a purchase from your order system, and expect a channel report to credit the campaign that drove it. There's no session to inherit from. The engagement figures fail the same way: Google advises including session_id and engagement_time_msec "to ensure accurate session and user engagement metrics in your reports, including Realtime", and warns that events sent without them "won't contribute correctly to metrics like Average engagement time or Engaged sessions" (Google for Developers, checked 13 August 2026).

There are four different clocks, and each one changes what your event is allowed to do

This is the part that survives no summary, so here it is in one place.

The Measurement Protocol has no single expiry window. Google's use-case documentation sets a different deadline per job, and missing one doesn't produce an error — it produces an event that quietly does less than you assumed (Google for Developers, checked 13 August 2026):

What you want the event to doNeeds session_id?Deadline
Inherit session attribution (source, medium, campaign, geo)YesWithin 24 hours of the session starting
Carry a User-ID onto the sessionYesSame business day, with timestamp_micros set between session start and end
Reach linked ad platforms (Google Ads, CM360)NoWithin 63 days of the latest online event
Count towards audience evaluationNo30 days for web streams, 42 days for app streams

On top of that, the payload's own timestamp_micros field is documented as accepting a time "up to 72 hours in the past" (Google for Developers, checked 13 August 2026), which is a tighter constraint than three of the four windows above. A conversion you confirm five days after the click can still be exported to Google Ads, and it cannot be backdated to the day it happened.

The two rows that need no session_id are the ones worth planning around. Offline conversion feeds and audience building work from client_id alone across a long window, which makes them the realistic jobs for a nightly batch. Session attribution does not; it's a same-day, near-real-time job or it's nothing.

The api_secret is a server-side credential and it has exactly one safe home

If the secret is in your page source, anybody can write to your property.

The endpoint is a plain HTTP POST with the credential in the query string: POST /mp/collect?measurement_id=MEASUREMENT_ID&api_secret=API_SECRET (Google for Developers, checked 13 August 2026). You create the secret in the data stream's Measurement Protocol API secrets section, and Google's instruction carries no hedge: "The api_secret is private. Don't expose it in the client-side code of your website or app" (Google for Developers, checked 13 August 2026).

There's no signature, no origin check and no rate identity beyond that string. Anyone holding it can post arbitrary events into your property, and you have no way to tell theirs from yours after the fact. So it lives in an environment variable on your server, or in a secret manager, and the request is made by your backend. It does not live in a GTM variable in a web container, a Next.js NEXT_PUBLIC_ value, or a mobile app binary.

While you're there, read the feature policy, because it has teeth. You "must not upload any data that allows Google to personally identify an individual (such as certain names, Social Security Numbers, email addresses, or any similar data)", nor "data that permanently identifies a particular device", and you "must not session stitch authenticated and unauthenticated sessions of your end users unless your end users have consented to such activity" (Google for Developers, checked 13 August 2026). That last clause is the one server-side implementations trip over, because joining a logged-in order record to an anonymous browsing session is precisely what people build the Measurement Protocol to do.

Consent is the trap here. The payload accepts a consent object with ad_user_data and ad_personalization set to GRANTED or DENIED, and if you omit it, "Google Analytics uses the consent settings from corresponding online interactions for the client or app instance" (Google for Developers, checked 13 August 2026). Inheritance needs an online interaction to inherit from — and it needs your browser-side consent signal to have been correct in the first place. Our free Consent Mode checker reports the consent state your tags actually set before and after a visitor chooses, which is the value your server events will silently adopt.

Server-side GTM and the Measurement Protocol answer different questions

Choose by where the event originates, not by which sounds more advanced.

Server-side tagging is "a way to instrument your tags to measure user activity wherever it happens" (Google for Developers, checked 13 August 2026): a container you host, receiving requests from the browser and fanning them out to destinations under your control. The browser still initiates the hit, so the tag still holds the identifiers and consent state the client had.

The Measurement Protocol is a raw endpoint into one property. Nothing initiates the request but your own code, which is why the documentation makes you supply client_id yourself and why session attribution has to be joined by hand.

That splits the decision cleanly. Events that happen in a browser and need to reach several destinations without a stack of third-party tags: server-side GTM. Events that happen where there is no browser — a payment confirmed by a webhook, a refund, a lead qualified in the CRM three days later, a kiosk — the Measurement Protocol, which Google lists as its use cases: tying online to offline behaviour, offline conversions, and "devices where automatic collection isn't available, such as kiosks and watches" (Google for Developers, checked 13 August 2026).

Plenty of setups run both, and that's the normal shape rather than a compromise. Neither is a workaround for tracking prevention. The Measurement Protocol needs the browser-side client_id to be useful at all, so whatever stopped the tag also starves the server call.

What to do this week

If you're already sending Measurement Protocol events, open Reports, filter to one of them and check the session source. A wall of "(not set)" means you're posting without a session_id from a live session, and the fix is to capture it client-side and carry it through your request rather than to change anything on the server.

If you're planning an implementation, write down which of the four jobs you actually need before you write any code, because the answer determines your deadline and whether session_id is required at all. Offline conversions into Ads and session attribution are different builds with different failure modes.

And grep your front-end bundle for the secret before you ship. Then make sure the event names you're posting match the recommended names Google publishes, because a server event carrying an invented name inherits every reporting limitation a browser event with an invented name would. Getting that chain right — from the consent signal, through the tagging layer, to what the bidding platform receives — is what we do.

Sources

  1. 1.Google for Developers — Measurement Protocol (GA4) overview · Checked 2026-08-13
  2. 2.Google for Developers — Measurement Protocol use cases · Checked 2026-08-13
  3. 3.Google for Developers — Send Measurement Protocol events to Google Analytics · Checked 2026-08-13
  4. 4.Google for Developers — Measurement Protocol reference (payload, consent, timestamp_micros) · Checked 2026-08-13
  5. 5.Google for Developers — Measurement Protocol, SDK, and User-ID Feature Policy · Checked 2026-08-13
  6. 6.Analytics Help — [GA4] Measurement Protocol · Checked 2026-08-13
  7. 7.Google for Developers — Server-side tagging · Checked 2026-08-13

Find out what your site leaks — in 30 seconds

Run the free consent checker on your own domain, or book a call and we'll walk your setup together.