GA4

GA4 Measurement Protocol: send an event and debug it

Send an event to GA4 with the Measurement Protocol, check it on Google's validation server, and see what it misses. Tested requests, limits and fixes.

GA4Vadym Kramarenko6 min read

GA4 Measurement Protocol: send an event and debug it

The GA4 Measurement Protocol is an HTTP API for sending events to Google Analytics 4 directly from a server. It is used for events a browser cannot send, such as offline purchases, refunds or CRM status changes. It supplements the Google tag and Google Tag Manager and does not replace them.

It also never tells you that an event is wrong. The endpoint answers a POST with a success status even when the payload is malformed, and the event can still be dropped later. The only way to find out whether a request is valid is to send it to Google’s validation server first. This page gives a request that was tested against that server, shows what the validator catches and what it lets through, and lists the reasons an accepted event can still be missing from your reports.

Everything here was tested or read from Google’s documentation in October 2026. Google changes this documentation, so check it before you rely on a limit.

What you need for the first request

What you need for the first request

Value Where to find it Notes
measurement_id Admin, Data streams, your web stream In the URL, like G-XXXXXXXXXX
api_secret Admin, Data streams, your stream, Measurement Protocol API secrets, Create Keep it private. Anyone who has it can send arbitrary events to your property
client_id The ID the Google tag generated for that browser In the JSON body. It should match the browser’s ID, or the event will not join that user’s activity

An app stream uses firebase_app_id in the URL and app_instance_id in the body in place of the first and third rows. The protocol accepts only POST requests. For data collected in the EU, use region1.google-analytics.com as the host.

Never put the api_secret in code that runs in a browser. From a browser, send events with the Google tag or Tag Manager instead, as in how to set up GA4 tags with Google Tag Manager.

A request that works

A request that works

curl -X POST 'https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=API_SECRET' \
  -H 'Content-Type: application/json' \
  -d '{
  "client_id": "1234567890.1700000000",
  "events": [{
    "name": "purchase",
    "params": {
      "transaction_id": "T-1001",
      "value": 49.9,
      "currency": "EUR",
      "session_id": "1700000000",
      "engagement_time_msec": 100,
      "items": [{"item_id": "SKU-1", "item_name": "Test item", "price": 49.9, "quantity": 1}]
    }
  }]
}'

Send transaction_id with a purchase so a retry does not create a duplicate; the failure is described in duplicate transactions in GA4. Google says to include session_id and engagement_time_msec: without them, events may still appear in some reports, but they do not count correctly toward metrics such as average engagement time or engaged sessions.

This request returns 204 and no body, whether or not it is valid. Do not read that as success.

The Turning Point

OWOX Data Marts

See your first report built in real time. 15 minutes.

  1. Connect your data warehouse
  2. Pick your metrics
  3. Get a live Google Sheets report

In the time it takes to write a ticket. Then imagine never writing that ticket again.

Book a Demo

We'll use your actual use case

Check it on the validation server first

Check it on the validation server first

Send the same body to the same path with /debug in front of mp/collect:

curl -X POST 'https://www.google-analytics.com/debug/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=API_SECRET' \
  -H 'Content-Type: application/json' \
  -d '{ ...the same body... }'

The response for the request above is:

{ "validationMessages": [] }

An empty array means the validator found no problem. Events sent to it do not appear in reports. Google says to leave validation_behavior out in production, to keep rejections down.

Google recommends strict checking in development, and it matters more than the recommendation suggests. These mistakes were each sent to the validator twice, once as written and once with "validation_behavior": "ENFORCE_RECOMMENDATIONS", using a made-up measurement ID and secret:

Mistake Default mode Strict mode
Event name starting with an underscore, _bad NAME_INVALID NAME_INVALID
No client_id VALUE_REQUIRED VALUE_REQUIRED
Reserved event name, first_visit NAME_RESERVED NAME_RESERVED
A parameter value of 101 characters nothing VALUE_TOO_LONG
A parameter name or an event name of 41 characters nothing NAME_TOO_LONG
26 parameters on one event nothing EXCEEDED_MAX_ENTITIES
26 user properties nothing EXCEEDED_MAX_ENTITIES
A user property name of 25 characters nothing NAME_TOO_LONG
A user property value of 37 characters nothing VALUE_TOO_LONG
timestamp_micros older than 72 hours nothing VALUE_INVALID

In default mode the validator reported three of these ten. If you test without the flag, a payload that breaks the length and count limits comes back clean.

A full response looks like this, for an event named first_visit:

{
  "validationMessages": [{
    "fieldPath": "events",
    "description": "Event at index: [0] has name [first_visit] which is reserved.",
    "validationCode": "NAME_RESERVED"
  }]
}

Google states that the validation server does not check the api_secret, and in these tests it did not check the measurement_id either: a made-up one passed. A request with a wrong secret or the wrong property passes.

What the validator lets through

What the validator lets through

These four returned an empty validationMessages array in both modes:

What was sent Why it is a problem
26 events in one request Google’s limit is 25 events per request
A screen_view event on a web stream Google allows screen_view only on app streams; a web stream uses page_view
A purchase with "value": "abc" The value should be a number
A purchase with no currency Revenue needs a currency

An empty array therefore means the payload parsed, not that GA4 will use the event. Check these four by hand.

Why an accepted event can be missing

Why an accepted event can be missing

Each of these comes from Google’s documentation, or from the tests above:

  1. The secret or the measurement ID is wrong. Neither the endpoint nor the validator says so.
  2. The client_id does not match the browser’s. Google joins Measurement Protocol events to online activity by client_id. If the tag has collected no device information for it, the event defaults to desktop on a web stream.
  3. There is no session_id or engagement_time_msec. Google says such events may not be fully reflected in Realtime user counts, and they do not count correctly toward engagement metrics.
  4. The timestamp is more than 72 hours old. In the default relaxed mode GA4 accepts the event and overrides its time to 72 hours ago. In strict mode it rejects it.
  5. The event arrives too late to be joined. Google says events meant to be joined with gtag.js or Firebase events should reach GA4 within 48 hours of the original client-side timestamp.
  6. The request is over a limit. Beyond 100 million non-conversion requests an hour for a property, the protocol silently ignores them for the rest of the hour.
  7. The name is reserved or belongs to the other stream type. Apart from the cases above, some event, parameter and user property names cannot be sent.

How long an accepted event takes to appear in reports is not stated in Google’s documentation, and it was not measured for this page.

Limits

Limits

Limit Value
Events per request 25
Parameters per event 25
User properties per request (Google’s page says per event; the validator message says per request) 25
Event and parameter names 40 characters, letters, digits and underscores, starting with a letter
Parameter value 100 characters (500 on a Google Analytics 360 property)
User property name and value 24 and 36 characters
Request body Under 130 kB
Backdating Up to 72 hours

What it cannot do

What it cannot do

The Measurement Protocol is meant to add to the data your tag collects, not to be a full replacement. Google notes that sending everything through it may give only partial reporting, and that the rules you set in the GA4 interface to create or rename events do not run on events sent this way. Your code has to send the final event names.

Google’s documentation now describes the protocol as in a finalized state with no plans for deprecation, and recommends the Data Manager API for new server-to-server integrations. If you are starting one, read that page before you build on this one.

Your New Normal

Turn your data into decisions.

Governed data marts give you the clean foundation ML needs to actually work.

  • No AI hallucinations
  • Analyst-governed definitions
  • Every number traces to SQL
Get started free

FAQ

Frequently Asked Questions

What is the GA4 Measurement Protocol?

The GA4 Measurement Protocol is a set of rules and specifications that allows businesses to send data to Google Analytics 4 programmatically, enabling data collection from various digital platforms.

Why would I use the Measurement Protocol?

The Measurement Protocol offers flexibility for data collection beyond standard web tracking, making it valuable for businesses that need data from diverse sources, such as mobile apps, IoT devices, or offline interactions, to be combined into their analytics.

How is the Measurement Protocol different from tracking codes?

Unlike tracking codes, which are typically implemented directly into web pages, the Measurement Protocol enables data collection from a wider range of sources, including mobile apps and other digital platforms, through HTTP requests.

Who wrote this

Vadym Kramarenko

Vadym Kramarenko · Growth Marketing Manager

Vadym Kramarenko is a Growth Marketing Manager at OWOX, where he drives user acquisition and product-led growth strategies. He hosts the OWOX podcast, interviewing analytics professionals about data-driven marketing, attribution, and reporting best practices. Vadym specializes in turning complex analytics concepts into practical, actionable marketing frameworks.