server-track-labby Canada Site Ops

GA4 Measurement Protocol payload builder

Build a GA4 Measurement Protocol request for a web stream and check it against Google's documented rules before you send it. Rules come only from Google's docs (fetched Oct 19, 2026): GA4 MP: Reference · GA4 MP: Send events (limitations) · GA4 MP: Validate events · GA4 MP: Recommended events.

Standalone tool. Nothing is sent or stored. This page makes no network calls with what you enter: it doesn't call /mp/collect or even /debug/mp/collect, it has no field for your API secret (the curl uses $GA4_API_SECRET), and no analytics run here. Honest status: the server-track-lab API forwards to the Meta Conversions API (live with your own pixel and token), Google via the Data Manager API (validate-only preview) and LinkedIn (dry-run). It does not forward to the GA4 Measurement Protocol.

Request

api_secret: not asked for and never sent from this page. The curl reads it from $GA4_API_SECRET; create it under Admin → Data Streams → your stream → Measurement Protocol → Create, and keep it on your server.

Events

Checks

JSON body


1. Test first: /debug/mp/collect

Same body, different URL. The validation server returns validationMessages (fieldPath, description, validationCode such as NAME_INVALID or VALUE_OUT_OF_BOUNDS); an empty array means no problems found. Events sent here never show up in reports. It does not check your api_secret. Set validation_behavior to ENFORCE_RECOMMENDATIONS while testing for the most feedback.


2. Then send: /mp/collect

Run this from your server, not from browser code (that would expose the api_secret). A 2xx response only means the request was received, not that the event was valid or processed.



GA4 Measurement Protocol vs gtag.js

gtag.js (or Google Tag Manager) runs in the visitor's browser. It sets the _ga cookie, starts sessions, records page views and engagement, and sends events as they happen. The Measurement Protocol is the opposite end: a plain HTTPS POST from your server to https://www.google-analytics.com/mp/collect with a measurement_id and api_secret in the query string and a JSON body. Nothing runs in the browser, so ad blockers, closed tabs and consent-banner timing don't affect delivery. The trade-off is that nothing is automatic either. There's no cookie, no session and no page context unless you send them.

That's why Google positions the Measurement Protocol as a way to augment tag-collected data, not replace it. Web events sent this way should belong to a user the tag has already seen. The request is keyed by client_id, the same ID the tag stores in the browser, and ideally carries the browser's session_id too.

When to use it

Don't use it to rebuild full browser tracking from the server. Page views, engagement time and session starts are what the tag is for. Note too that Google's Measurement Protocol docs now say it has reached "a mature, finalized product state" with no plans for deprecation, and recommend the Data Manager API for future-proof server-to-server integrations.

Reuse the client_id, or lose the attribution

The most common Measurement Protocol mistake is inventing a client_id on the server. GA4 then sees a brand-new user with no source, medium or campaign, and your conversion lands under "(not set)" or "Direct". Instead, read the ID in the browser while the user is on your site: gtag('get', 'G-XXXXXXXXXX', 'client_id', cb) (or the session with 'session_id'), or the Analytics Client ID variable in Tag Manager. Send it to your backend with the form or checkout, store it next to the lead or order, and reuse it when the later event fires. Google recommends the two-number form, like 1234567890.1712345678. That's the last two parts of a _ga cookie value like GA1.1.1234567890.1712345678, and the converter above extracts it. Add user_id if the person is logged in, so GA4 can join their devices. Use your internal account ID, never an email address.

Common pitfalls

Related: Google Enhanced Conversions builder · Meta CAPI payload builder · LinkedIn Conversions payload builder · event_id generator · Form & CRM conversions guide · Stripe webhooks guide

Server-side conversions for ad platforms? server-track-lab is a separate product: one POST /api/v1/track call normalizes, hashes and dedupes your conversions, then forwards them to the Meta Conversions API (live with your own pixel and token). Google gets a Data Manager API validate-only preview and LinkedIn a dry-run preview. It does not send to GA4. Free for 1,000 events a month. Get a free API key · API docs

FAQ

Does this page send my event to Google Analytics?

No. Everything runs in your browser. The page never calls /mp/collect or /debug/mp/collect, has no field for your API secret, and loads no analytics. Copy the curl and run it yourself; it reads the secret from a $GA4_API_SECRET environment variable.

Does server-track-lab forward events to GA4?

No. server-track-lab forwards to the Meta Conversions API (live with your own pixel and token), builds a Google Data Manager API validate-only preview, and builds a LinkedIn dry-run preview. It does not send to the GA4 Measurement Protocol. This builder is a standalone tool.

How far back can timestamp_micros go?

Google's docs say events and user properties can be backdated up to 72 hours. With the default RELAXED validation, older timestamps are overridden to 72 hours ago; with ENFORCE_RECOMMENDATIONS the event is rejected. Events meant to join gtag.js events should arrive within 48 hours of the original client-side event.

Why does /mp/collect return 2xx for a broken event?

The Measurement Protocol returns a 2xx status if the HTTP request is received, even when the payload is malformed or not processed. Send the same body to /debug/mp/collect first: it returns validationMessages, and its events never appear in reports. Note that the validation server doesn't check your api_secret.

What client_id should I use?

The one the user's browser already has. Google recommends two positive numbers joined by a period, which you get with gtag('get', 'G-XXXXXXXXXX', 'client_id', callback), or the Analytics Client ID variable in Google Tag Manager. A new random ID creates a new, unattributed user.

What are the main limits?

Per Google's docs: up to 25 events per request, 25 parameters per event, 25 user properties per request, event and parameter names up to 40 characters (starting with a letter; letters, numbers and underscores only), parameter values up to 100 characters (500 on GA4 360), user property names up to 24 and values up to 36 characters, 10 custom parameters per item, and a POST body under 130kB.