GA4 Measurement Protocol: Sending Events From Your Server
The Measurement Protocol lets your server, CRM or back office send events straight to Google Analytics 4, for things that never happen in a browser, such as a refund, a signed contract or a renewal. This guide covers what it is for and not for, the API secret and client ID, Google's limits, late events, attribution, consent and how to test it.
This guide is based on Google's developer documentation: the Measurement Protocol overview, Send Measurement Protocol events and the protocol reference. Google's pages on use cases, validation and troubleshooting are linked where they are used. It covers web streams (a site tagged with the Google tag or Tag Manager); app streams work the same way with Firebase IDs.
- What the Measurement Protocol is
- What it is for, and what it is not for
- What you need: API secret, Measurement ID and client ID
- Sending an event
- Limits and reserved names
- Timestamps and late events
- Sessions, attribution, User-ID and audiences
- Consent and privacy
- Validating and testing
- Frequently asked questions
What the Measurement Protocol is
Most GA4 data comes from a tag in the visitor's browser. The Measurement Protocol is the other door: your own system sends events "directly to Google Analytics servers in HTTP requests", and they show up in your reports next to the tagged data. Google lists four typical uses:
- Tying online behaviour to offline behaviour.
- Measuring interactions on both the client side and the server side.
- Sending events that happen outside normal user interaction, such as offline conversions.
- Sending events from devices where automatic collection is not available, such as kiosks and watches.
On its status, Google's documentation says the protocol "has reached a mature, finalized product state" and will stay running "with no plans for deprecation". For new server-to-server integrations, though, Google recommends the Data Manager API. Its upgrade comparison lists the differences: the Data Manager API needs no API secret, supports encryption, can send to several destinations in one request and reports errors at once, while the Measurement Protocol only reports errors through its validation server. If you are new to GA4 itself, start with our Google Analytics 4 basics.
What it is for, and what it is not for
Google is direct about this: the protocol is meant "to augment automatic collection through gtag, Tag Manager, and Google Analytics for Firebase, not to replace it." You need the tag on your site as well, and most of the useful features depend on it:
- Location and device. GA4 joins the latest location and device details collected by your tag to each Measurement Protocol event through the client ID. If the tag never collected device information, it defaults to desktop for web streams.
- Ad identifiers and privacy settings. Ad click identifiers (Google names GBRAID and WBRAID) and settings such as non-personalized ads are carried over from the online interactions in the same way.
- Remarketing. Same-device remarketing works when Google signals is on; cross-device remarketing needs a User-ID.
Sending everything only through the protocol is possible, but Google warns that "only partial reporting may be available." Two more points from the overview: GA4's rules for creating or modifying events in the admin screens are not triggered by Measurement Protocol events, so your code must send the final event names itself; and some names that GA4 collects automatically cannot be sent at all (see the limits section).
The protocol is also not for browsers. Google says the API secret must not be exposed "in the client-side code of your website or app", because anyone who has it can send spam data into your property. In the browser, use the Google tag or Google Tag Manager. The one exception Google names is Manifest V3 Chrome extensions, which cannot load gtag.js and should use the Measurement Protocol instead.
In practice, the protocol suits events your server knows about and the browser does not: a refund issued from the admin area, an order paid by invoice, a lead marked as qualified in your CRM. If those events need to reach Google Ads as conversions, our offline conversion import guide covers Google Ads' own route, and our CRM and website integration guide covers getting form data into the CRM in the first place. For batches you upload as files rather than send as they happen, such as daily point-of-sale events or CRM fields, see our GA4 data import guide.
What you need: API secret, Measurement ID and client ID
Each request carries three identifiers. For a web stream:
| Identifier | Where it goes | What it is |
|---|---|---|
api_secret | URL query | Authenticates the request. Created per data stream in GA4. |
measurement_id | URL query | The web stream's ID, usually starting with G-. Google notes it "is not the same as your Stream ID." |
client_id | JSON body | The ID the Google tag gave this browser. It should match the tag's value so the event joins the right visitor. |
For app streams the URL uses firebase_app_id and the body uses app_instance_id, both from the Firebase SDK.
To create a secret, go to Admin, then Data collection and modification > Data streams, pick the stream, open Measurement Protocol API secrets, click Create, give it a nickname and copy the value. The reference says the secret should be "regularly updated to avoid excessive SPAM", and secrets can be revoked.
The client ID is the hard part, because it lives in the visitor's browser. Google's tag reference says it is stored by default in the first-party Analytics cookie "with a two-year expiration". The protocol reference recommends the format of two positive numbers joined by a period, read with gtag's get command on the site, or with the Analytics Client ID built-in variable in Tag Manager; it also accepts the full value of the client ID cookie. A common pattern is to capture the client ID with a form submission or order, store it with the record, and send it back with the server event later. If your site has logged-in users, also send user_id, as our GA4 User-ID guide explains.
Sending an event
The protocol only accepts HTTPS POST requests to https://www.google-analytics.com/mp/collect, with measurement_id and api_secret in the URL. Google gives region1.google-analytics.com as the host to use "if you want your data to be collected in the EU". The body is JSON. This is Google's own example:
{
"client_id": "CLIENT_ID",
"events": [
{
"name": "login",
"params": {
"method": "Google",
"session_id": "SESSION_ID",
"engagement_time_msec": 100
}
}
]
}
Two parameters in that example matter more than they look. The reference says to include session_id and engagement_time_msec so the events count properly towards session and engagement metrics, including Realtime; without them, events "won't contribute correctly" to metrics such as average engagement time or engaged sessions. Optional top-level fields include user_id, user_properties, consent, user_location or ip_override for location, and device or user_agent for device details. Use the same recommended event names and parameters as the tag does: a server-side refund, for example, is the refund event described in our GA4 ecommerce tracking guide. Custom parameters work too, and must be registered as custom dimensions to show in reports, as our GA4 custom dimensions guide explains.
One behaviour catches people out. The protocol returns a 2xx status if the request was received, and "doesn't return an error code if the payload is malformed, or if the data is incorrect or not processed." A success response does not mean the event was recorded. That is why the validation server exists (see testing below). Google also says that if you do not get a 2xx code, fix the request and "Don't retry the same request."
Limits and reserved names
Google's limits for standard properties:
| What | Limit |
|---|---|
| Events per request | 25 |
| Parameters per event | 25 |
| User properties per request | 25; names up to 24 characters, values up to 36 |
| Event and parameter names | Up to 40 characters, letters, numbers and underscores only, starting with a letter |
| Parameter values | Up to 100 characters (500 on GA4 360) |
| Custom parameters per item | 10 |
| Request body | Smaller than 130 kB |
| Non-conversion requests | 100 million per hour per property (not on 360); above that, they are silently ignored for the rest of the hour |
Some names are reserved. Events such as session_start, first_visit, user_engagement and error cannot be sent; parameter names cannot start with an underscore, firebase_, ga_, google_ or gtag.. On web streams, screen_view, ad_impression and in_app_purchase are app-only: use page_view and purchase instead. You do not need session_start anyway: per Google, a new session_id starts a new session by itself.
Timestamps and late events
Every event gets a time from the first of these that exists: the event's own timestamp_micros, the request's timestamp_micros, or the moment Google received the request. The value is in microseconds, "not milliseconds", and should only be set for events that happened in the past.
- Events and user properties can be backdated up to 72 hours.
- With the default
RELAXEDvalidation, an older timestamp is accepted but moved to 72 hours ago. WithENFORCE_RECOMMENDATIONS, the event is rejected. - Events meant to be joined with tagged events "should be received by Google Analytics within 48 hours of the original client-side event timestamp". Later ones may not be processed as expected, "particularly for purposes like conversion attribution."
So a nightly batch job is fine, while a weekly export of last week's sales will lose its original dates and much of its attribution.
Sessions, attribution, User-ID and audiences
Google's use cases page sets out what each goal needs. "Business day" means the day in your property's time zone.
| Goal | session_id | Send the request by |
|---|---|---|
| Event gets the session's source, medium, campaign and location | Required | 24 hours after the session started |
| Add a User-ID to events | Required | End of the business day the session started |
| Include the event in exports to Google Ads or Campaign Manager 360 | Not required | 63 days after the latest online event, and inside the key event's attribution window |
| Use the event in audience conditions | Not required | 30 days after the latest online event (42 for app streams) |
For the first two goals, any overridden timestamp must fall between the session's start and end; for the last two, within the last 72 hours. Google's example for session attribution: a session that started at 11:15 AM on Monday needs the request before 11:15 AM on Tuesday. The ad export case is how a server-side purchase or qualified lead can still count towards your Google Ads results through GA4; our GA4 attribution guide covers attribution windows, and our GA4 audiences guide covers audience conditions.
Consent and privacy
A request can carry a consent object with ad_user_data and ad_personalization, each GRANTED or DENIED. If you leave it out, GA4 "uses the consent settings from corresponding online interactions" for that client ID. The older non_personalized_ads field is deprecated in favour of ad_personalization. Whatever location or device details you send, GA4 still applies the property's granular location and device data settings.
Google's Measurement Protocol policy adds rules that apply to every implementation:
- Tell users which Google Analytics features you use and what data you collect, and get consent or give them a way to opt out.
- Do not upload data that lets Google personally identify someone, "such as certain names, Social Security Numbers, email addresses", or IDs that permanently identify a device.
- Do not stitch logged-in and logged-out sessions together unless users have consented and the law allows it.
The policy says breaking these rules can mean termination of your Google Analytics account and loss of its data. Keep order numbers and CRM IDs free of email addresses, and make sure your server only sends events for visitors whose consent allows it. Our cookie consent banners guide covers the browser side.
Validating and testing
Because the live endpoint accepts almost anything, test in this order:
- Validate the structure. Send the same request to
/debug/mp/collectinstead of/mp/collect. Google's validation page says these events "don't show up in reports", and the response lists problems with a field path, a description and a code such asNAME_INVALID,NAME_RESERVED,VALUE_OUT_OF_BOUNDSorEXCEEDED_MAX_ENTITIES. Google recommends settingvalidation_behaviortoENFORCE_RECOMMENDATIONSwhile developing, and leaving it out in production to minimise rejected data. The GA4 Event Builder does the same check in a form. - Check the keys yourself. The validation server "does not validate the api_secret or measurement_id."
- Send a real event. Google's verification page says the event needs a client ID "that has already been used to send an event from gtag.js", so capture one from a real visit. Events "typically show up within a few seconds" in Reports > Realtime.
- Use DebugView for detail. Add
"debug_mode": trueand a positiveengagement_time_msecto the test event's parameters, then watch it as our GA4 DebugView guide shows.
If nothing arrives, Google's troubleshooting page lists the usual causes: a secret from a different stream (each stream has its own), a secret someone revoked, a secret copied with the wrong case (it is case-sensitive), or a client ID from another property. advertising_id is not a valid device identifier. And if you send Measurement Protocol requests to a server-side Tag Manager container rather than to Google's endpoint, the container does not support all the endpoint's features, such as joining location and device details from your tag.
Frequently asked questions
Is the GA4 Measurement Protocol being deprecated?
No. Google says it has reached a mature, finalized state and has no plans for deprecation, but recommends the Data Manager API for new server-to-server integrations.
Can I use the Measurement Protocol instead of the GA4 tag?
Google says it is meant to augment the tag, not replace it. Sending only server events is possible, but reporting may be partial, because location, device, consent and ad identifiers are joined from tagged events through the client ID.
Can I call the Measurement Protocol from the browser?
No. The API secret must stay private; exposing it lets anyone send spam data to your property. Use the Google tag or Tag Manager in the browser. Google's one exception is Manifest V3 Chrome extensions.
Why do my Measurement Protocol events not show up?
The endpoint returns success even for bad data. Check the request against the validation server, then check the API secret, Measurement ID and client ID belong to the same stream and property, and that the client ID came from a real gtag.js visit.
How late can I send an event?
Timestamps can go back 72 hours. For session attribution, send within 24 hours of the session start; for exports to Google Ads, within 63 days of the latest online event and inside the attribution window.
Server-side events need a site and back end built to pass the right IDs along. See our website development and web app development services and all our services, or email [email protected].