Server-side events · Platform reference
GA4 Measurement Protocol: events, fields and dedup rules
The GA4 Measurement Protocol lets a server POST events to a GA4 web stream (measurement_id + api_secret) or app stream, joined to the visitor through the client_id that the Google tag created. It's meant to add to tagging, not replace it. Events arrive but show up as unassigned or (not set), or never reach linked ad platforms, when client_id or session_id don't come from the real tag, when the event is sent after the session or export windows, or when the payload is malformed: the production endpoint returns no HTTP errors.
Read from the official documentation on 9 November 2026. Sources are listed at the end.
Endpoint and authentication
POST https://www.google-analytics.com/mp/collect?measurement_id={MEASUREMENT_ID}&api_secret={API_SECRET} (EU: region1.google-analytics.com)
api_secret query parameter (a Measurement Protocol API secret for the data stream) plus measurement_id; app streams use firebase_app_id instead
Standard event names
Spelled exactly as Google Analytics 4 expects them. A near miss is treated as a different event.
| Event | Use it for |
|---|---|
| purchase | recommended event; transaction_id and items required, value typically required, currency required when value is set |
| refund | recommended online-sales event |
| begin_checkout | recommended online-sales event |
| add_to_cart | recommended online-sales event |
| add_payment_info | recommended online-sales event |
| add_shipping_info | recommended online-sales event |
| view_item | recommended online-sales event |
| sign_up | recommended for all properties |
| login | recommended for all properties |
| search | recommended for all properties |
| session_start / first_visit / user_engagement | RESERVED: can't be sent via Measurement Protocol |
Required and recommended fields
| Field | What it needs |
|---|---|
| api_secret | Query parameter; the validation server does not check it |
| measurement_id | Query parameter for web streams |
| client_id | Body. For web streams it should match the ID the Google Analytics tag generated on your site |
| events[].name | 40 characters or fewer, alphanumeric; reserved names rejected |
| events[].params.session_id | Needed to attribute the event to a session; must be a positive number from the client-side tag |
| events[].params.engagement_time_msec | Recommended alongside session_id, or engagement metrics are off |
| timestamp_micros | Optional Unix microseconds; can backdate up to 72 hours |
| consent.ad_user_data / consent.ad_personalization | GRANTED or DENIED; non_personalized_ads is deprecated in favour of consent.ad_personalization |
| user_id | Optional; needed for cross-device remarketing |
| validation_behavior | RELAXED (default) or ENFORCE_RECOMMENDATIONS |
Match keys and hashing
| Key | Normalise and hash |
|---|---|
| client_id | Not hashed. Read the value the Google tag generated |
| user_id | Not hashed. Your own UTF-8 user ID |
| user_data | User-provided data object (field-level rules not covered on the pages fetched) |
| ip_override / user_location / device | Not hashed. Used for geo and device; user_location takes precedence over ip_override |
Click ids
| Click id | Where it comes from |
|---|---|
| GBRAID / WBRAID (via the client_id join) | Measurement Protocol events are joined to online interactions by client_id (or app_instance_id), and advertising identifiers such as GBRAID/WBRAID carry over through that join. The MP reference lists no click-ID field on the event itself |
Deduplication
- The Measurement Protocol reference documents no event_id or deduplication field, so plan for each event to come from only one channel (gtag or MP), not both.
- For purchase, the required transaction_id is the unique identifier of a transaction.
Time limits and batch sizes
- Events and user properties can be backdated up to 72 hours with timestamp_micros. Beyond that, RELAXED overrides the time to 72 hours ago and ENFORCE_RECOMMENDATIONS rejects the event.
- Events meant to join up with gtag.js or Firebase events (for attribution) should reach Google Analytics within 48 hours of the original client-side event; later ones may not be processed as expected.
- Session attribution: send session_id within 24 hours of the session start.
- Export to advertising platforms: send no later than 63 days after the latest online event, and within the key event's attribution window.
- Audiences on a web stream: send no later than 30 days after the latest online event for that client_id.
- Max 25 events per request, 25 params per event, 25 user properties; post body under 130kB; parameter values 100 characters or fewer (standard property).
How to test before you trust it
- Measurement Protocol validation server: POST the same payload to /debug/mp/collect. The response has a validationMessages array (fieldPath, description, validationCode such as NAME_INVALID, VALUE_REQUIRED, NAME_RESERVED); an empty array means valid. Events sent here don't show up in reports, and api_secret and firebase_app_id aren't checked.
Why events arrive but don't attribute
- The production /mp/collect endpoint returns no HTTP error codes even for malformed events, so a 2xx response proves nothing. Validate against /debug/mp/collect first.
- No session_id, or one sent more than 24 hours after the session started, so the event isn't tied to a session and its traffic source can show as (not set) or unassigned.
- A made-up client_id instead of the one the Google tag generated, so the event can't be joined to the visitor's ad click and campaign data.
- Key events sent more than 63 days after the latest online event, or outside the key event's attribution window, aren't exported to advertising platforms.
- timestamp_micros more than 72 hours old: the time is silently moved to 72 hours ago (RELAXED) or the event is dropped (ENFORCE_RECOMMENDATIONS).
- Reserved event or parameter names (session_start, first_visit, names starting with _ / ga_ / google_ / firebase_ / gtag.) are rejected.
- Event-creation or modification rules configured in GA4 aren't triggered by Measurement Protocol events, so your server has to apply the same logic itself.
- The validation server doesn't check api_secret, so a payload can pass validation and still be ignored in production because the secret is wrong.
Sources
- Google Analytics: Send Measurement Protocol events
- Google Analytics: Validate events
- Google Analytics: Measurement Protocol reference
- Google Analytics: Measurement Protocol overview
- Google Analytics: Measurement Protocol use cases
- Google Analytics: Measurement Protocol events reference
Platforms change these rules without notice. If a source says something different from this page, the source wins.