--- name: ga4-measurement-protocol description: Complete guide to GA4 Measurement Protocol for server-side event tracking including API authentication, request format, validation, and implementation examples. Use when implementing server-side tracking, sending events from backend, working with Measurement Protocol API, integrating CRM with GA4, or tracking offline conversions. Covers API secrets, debug endpoint, Python/Node.js/PHP examples, and rate limits. --- # GA4 Measurement Protocol ## Overview The GA4 Measurement Protocol allows server-side event collection, enabling data transmission to GA4 from any HTTP-capable environment including backend servers, mobile apps, kiosks, and IoT devices. ## When to Use This Skill Invoke this skill when: - Implementing server-side event tracking - Sending events from backend/server environments - Tracking offline conversions or transactions - Integrating CRM systems with GA4 - Sending events from mobile app backends - Tracking server-to-server transactions - Implementing purchase tracking from payment processors - Tracking subscription renewals or recurring payments - Sending lead generation events from forms backend - Implementing custom server-side analytics - Working with headless CMS or API-first architectures - Debugging Measurement Protocol requests - Validating event payloads before production ## Core Capabilities ### API Endpoints **Production Endpoint:** ``` POST https://www.google-analytics.com/mp/collect ``` **Debug Endpoint (Validation):** ``` POST https://www.google-analytics.com/debug/mp/collect ``` **Key Difference:** Debug endpoint returns validation messages without storing data. ### Authentication Requirements **Two Credentials Required:** 1. **Measurement ID** (format: `G-XXXXXXXXXX`) - Find in: GA4 Admin → Data Streams → Web Stream details 2. **API Secret** - Generate in: Data Streams → Measurement Protocol API secrets → Create **Generating API Secret:** 1. GA4 Admin → Data Streams 2. Click your data stream 3. Scroll to "Measurement Protocol API secrets" 4. Click "Create" 5. Enter nickname (e.g., "Server-side tracking") 6. Click "Create" 7. **Copy secret immediately** (cannot retrieve later) ### Request Structure **URL Format:** ``` https://www.google-analytics.com/mp/collect?measurement_id={MEASUREMENT_ID}&api_secret={API_SECRET} ``` **Headers:** ``` Content-Type: application/json ``` **Body (JSON):** ```json { "client_id": "unique_client_identifier", "user_id": "optional_user_id", "timestamp_micros": "1234567890123456", "user_properties": { "property_name": { "value": "property_value" } }, "consent": { "ad_storage": "granted", "analytics_storage": "granted" }, "events": [ { "name": "event_name", "params": { "parameter_name": "parameter_value", "value": 123.45, "currency": "USD" } } ] } ``` ### Required Fields - **client_id**: Unique identifier for client (UUID recommended) - **events**: Array of event objects (max 25 events per request) - **events[].name**: Event name (string, ≤40 characters) ### Optional Fields - **user_id**: User identifier for cross-device tracking - **timestamp_micros**: Event timestamp in microseconds (UTC) - **user_properties**: User-level properties - **consent**: Consent status (ad_storage, analytics_storage) ### Common Event Parameters | Parameter | Type | Description | |-----------|------|-------------| | `session_id` | string | Session identifier | | `engagement_time_msec` | integer | Engagement time in milliseconds | | `page_location` | string | Full URL | | `page_title` | string | Page title | | `value` | number | Monetary value | | `currency` | string | ISO 4217 currency code (USD, EUR) | | `transaction_id` | string | Unique transaction ID | | `items` | array | E-commerce items array | ### Python Implementation **Using Requests Library:** ```python import requests import json import uuid MEASUREMENT_ID = "G-XXXXXXXXXX" API_SECRET = "your_api_secret" ENDPOINT = f"https://www.google-analytics.com/mp/collect?measurement_id={MEASUREMENT_ID}&api_secret={API_SECRET}" def send_event(event_name, params=None): payload = { "client_id": str(uuid.uuid4()), "events": [{ "name": event_name, "params": params or {} }] } response = requests.post( ENDPOINT, headers={"Content-Type": "application/json"}, data=json.dumps(payload) ) return response.status_code == 204 # Send page view send_event("page_view", { "page_location": "https://example.com/page", "page_title": "Example Page" }) # Send purchase send_event("purchase", { "transaction_id": "T_12345", "value": 99.99, "currency": "USD", "items": [{ "item_id": "SKU_123", "item_name": "Product Name", "price": 99.99, "quantity": 1 }] }) ``` **Using ga4mp Library:** ```python # Install: pip install ga4mp from ga4mp import GtagMP ga = GtagMP( measurement_id="G-XXXXXXXXXX", api_secret="your_api_secret", client_id="unique_client_id" ) # Send event ga.send_event( event_name="purchase", event_parameters={ "transaction_id": "T_12345", "value": 99.99, "currency": "USD", "items": [{ "item_id": "SKU_123", "item_name": "Product Name", "price": 99.99, "quantity": 1 }] } ) ``` ### Node.js Implementation ```javascript const axios = require('axios'); const { v4: uuidv4 } = require('uuid'); const MEASUREMENT_ID = 'G-XXXXXXXXXX'; const API_SECRET = 'your_api_secret'; const ENDPOINT = `https://www.google-analytics.com/mp/collect?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`; async function sendEvent(eventName, params = {}) { const payload = { client_id: uuidv4(), events: [{ name: eventName, params: params }] }; try { const response = await axios.post(ENDPOINT, payload, { headers: { 'Content-Type': 'application/json' } }); return response.status === 204; } catch (error) { console.error('Error sending event:', error); return false; } } // Send purchase event sendEvent('purchase', { transaction_id: 'T_12345', value: 99.99, currency: 'USD', items: [{ item_id: 'SKU_123', item_name: 'Product', price: 99.99, quantity: 1 }] }); ``` ### PHP Implementation ```php setTransactionId('T_12345') ->setValue(99.99) ->setCurrency('USD'); $request = new MeasurementRequest(); $request->setClientId('unique_client_id') ->addEvent($event); $service->send($request); ?> ``` ### Validation with Debug Endpoint **Send to Debug Endpoint:** ```bash curl -X POST "https://www.google-analytics.com/debug/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=YOUR_SECRET" \ -H "Content-Type: application/json" \ -d '{ "client_id": "test_client", "events": [{ "name": "test_event", "params": { "test_param": "test_value" } }] }' ``` **Response Format:** ```json { "validationMessages": [ { "fieldPath": "events[0].name", "description": "Event name must be 40 characters or fewer", "validationCode": "NAME_INVALID" } ] } ``` **Empty Response = Valid:** - No validationMessages = payload valid - Status 200 = request processed ### Validation Codes | Code | Description | Fix | |------|-------------|-----| | `NAME_INVALID` | Invalid event/parameter name | Use lowercase, underscores, ≤40 chars | | `NAME_RESERVED` | Reserved name used | Check GA4 reserved names list | | `VALUE_INVALID` | Invalid parameter value | Check data type, format | | `VALUE_REQUIRED` | Required value missing | Add required parameter | | `VALUE_OUT_OF_BOUNDS` | Value exceeds limits | Check numeric ranges | | `EXCEEDED_MAX_ENTITIES` | Too many events | Max 25 events per request | ### Best Practices 1. **Always Validate First:** - Use debug endpoint before production - Test with sample data - Verify response is empty (valid) 2. **Use Consistent client_id:** - Same user = same client_id across sessions - Store in database for logged-in users - Use UUID format for anonymity 3. **Include session_id:** - Maintain session continuity - Generate unique session ID - Keep consistent within session 4. **Batch Events:** - Send up to 25 events per request - More efficient than individual requests - Reduces API calls 5. **Handle Errors Gracefully:** - Implement retry logic with exponential backoff - Log failed requests - Queue events for retry 6. **Set Proper Timestamps:** - Use `timestamp_micros` for historical data - Convert to microseconds: `timestamp_ms * 1000` - Max 3 days in past, 72 hours in future 7. **Respect Consent:** - Set consent parameters appropriately - Match frontend consent status - Required for GDPR compliance ## Integration with Other Skills - **ga4-setup** - Initial GA4 property and data stream setup - **ga4-debugview** - Testing Measurement Protocol events in DebugView - **ga4-recommended-events** - Sending recommended event structures - **ga4-custom-events** - Server-side custom event implementation - **ga4-user-tracking** - Implementing User ID server-side - **ga4-privacy-compliance** - Setting consent parameters correctly - **ga4-bigquery** - Analyzing server-side events in BigQuery ## References - **references/measurement-protocol-complete.md** - Full API reference and examples - **references/authentication-setup.md** - API secrets and authentication guide - **references/event-validation.md** - Validation patterns and troubleshooting - **references/implementation-examples.md** - Real-world implementation patterns (Python, Node.js, PHP) - **references/rate-limits-best-practices.md** - Rate limits, batching, and optimization ## Quick Reference **Generate API Secret:** Admin → Data Streams → Measurement Protocol API secrets → Create **Endpoint:** - Production: `/mp/collect` - Debug: `/debug/mp/collect` **Required Fields:** - client_id (UUID recommended) - events array - event name **Max Limits:** - 25 events per request - 40 characters per event name - 25 event parameters per event - 25 user properties per request **Validation:** - Send to debug endpoint - Empty response = valid - Check validationMessages array