Skip to content
Back to skills

2547 Measurement Protocol A5b644a5

ASecurity

Complete guide to GA4 Measurement Protocol for server-side event tracking.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 31, 2026
developmentjavascriptpythongojavaphpbashnodeapidatabasefrontend

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add tools-only/X-Skills --skill 2547-measurement-protocol_a5b644a5 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2547 Measurement Protocol A5b644a5?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2547 Measurement Protocol A5b644a5
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2547-measurement-protocol-a5b644a5/badge)](https://www.skillsdirectory.com/skills/tools-only-2547-measurement-protocol-a5b644a5)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# GA4 Measurement Protocol

Complete guide to GA4 Measurement Protocol for server-side event tracking.

## Overview

The GA4 Measurement Protocol allows server-side event collection, enabling data transmission to GA4 from any HTTP-capable environment including backend servers, mobile app backends, kiosks, and IoT devices.

## When to Use Measurement Protocol

| Use Case | Description |
|----------|-------------|
| Server-side tracking | Events from backend systems |
| Offline conversions | Import CRM/POS data |
| Payment processing | Track post-checkout events |
| Subscription renewals | Server-initiated events |
| Lead enrichment | Enhance leads from backend |
| IoT devices | Non-browser environments |
| Headless architectures | API-first systems |

## API Endpoints

### Production Endpoint

```
POST https://www.google-analytics.com/mp/collect
```

### Debug Endpoint

```
POST https://www.google-analytics.com/debug/mp/collect
```

**Key Difference:** Debug returns validation messages without storing data.

## Authentication

### Required Credentials

1. **Measurement ID** (G-XXXXXXXXXX)
   - Location: GA4 Admin -> Data Streams -> Web Stream

2. **API Secret**
   - Location: Data Streams -> Measurement Protocol API secrets

### 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** (shown once only)
8. Store securely

## Request Structure

### URL Format

```
https://www.google-analytics.com/mp/collect?measurement_id={MEASUREMENT_ID}&api_secret={API_SECRET}
```

### Headers

```
Content-Type: application/json
```

### Request 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 and Optional Fields

### Required Fields

| Field | Type | Description |
|-------|------|-------------|
| client_id | string | Unique client identifier (UUID recommended) |
| events | array | Array of event objects (max 25) |
| events[].name | string | Event name (max 40 chars) |

### Optional Fields

| Field | Type | Description |
|-------|------|-------------|
| user_id | string | User ID for cross-device |
| timestamp_micros | integer | Event timestamp (microseconds) |
| user_properties | object | User-level properties |
| consent | object | Consent status |
| non_personalized_ads | boolean | Disable ad personalisation |

## Common Event Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| session_id | string | Session identifier |
| engagement_time_msec | integer | Engagement time (ms) |
| page_location | string | Full URL |
| page_title | string | Page title |
| value | number | Monetary value |
| currency | string | ISO 4217 code |
| transaction_id | string | Unique transaction ID |
| items | array | E-commerce items |

## Implementation Examples

### 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(client_id, event_name, params=None):
    payload = {
        "client_id": client_id,
        "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(
    client_id="user_123.session_456",
    event_name="page_view",
    params={
        "page_location": "https://example.com/page",
        "page_title": "Example Page"
    }
)

# Send purchase
send_event(
    client_id="user_123.session_456",
    event_name="purchase",
    params={
        "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(clientId, eventName, params = {}) {
  const payload = {
    client_id: clientId,
    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('client_123', '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
<?php
// Using php-GA4-Measurement-Protocol library
// Install: composer require br33f/php-ga4-measurement-protocol

use Br33f\Ga4\MeasurementProtocol\Dto\Event\PurchaseEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\MeasurementRequest;
use Br33f\Ga4\MeasurementProtocol\Service;

$measurementId = 'G-XXXXXXXXXX';
$apiSecret = 'your_api_secret';

$service = new Service($apiSecret, $measurementId);

$event = new PurchaseEvent();
$event->setTransactionId('T_12345')
      ->setValue(99.99)
      ->setCurrency('USD');

$request = new MeasurementRequest();
$request->setClientId('unique_client_id')
        ->addEvent($event);

$service->send($request);
?>
```

### cURL Example

```bash
curl -X POST "https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
  "client_id": "client_123",
  "events": [{
    "name": "purchase",
    "params": {
      "transaction_id": "T_12345",
      "value": 99.99,
      "currency": "USD"
    }
  }]
}'
```

## 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
- Production returns 204 (no content)

## Validation Codes

| Code | Description | Fix |
|------|-------------|-----|
| NAME_INVALID | Invalid event/parameter name | snake_case, max 40 chars |
| NAME_RESERVED | Reserved name used | Check reserved names |
| VALUE_INVALID | Invalid parameter value | Check data type |
| 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 per request |

## Best Practices

### 1. Always Validate First

```python
DEBUG_ENDPOINT = f"https://www.google-analytics.com/debug/mp/collect?measurement_id={MEASUREMENT_ID}&api_secret={API_SECRET}"

def validate_event(payload):
    response = requests.post(
        DEBUG_ENDPOINT,
        headers={"Content-Type": "application/json"},
        data=json.dumps(payload)
    )
    return response.json()
```

### 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

```python
payload = {
    "client_id": "client_123",
    "events": [
        {"name": "event_1", "params": {}},
        {"name": "event_2", "params": {}},
        {"name": "event_3", "params": {}}
    ]  # Up to 25 events per request
}
```

### 5. Handle Errors Gracefully

```python
def send_with_retry(payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(ENDPOINT, json=payload)
            if response.status_code == 204:
                return True
        except Exception as e:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)  # Exponential backoff
            else:
                log_error(e, payload)
    return False
```

### 6. Set Proper Timestamps

```python
import time

# For historical data (max 3 days past)
timestamp_micros = int(time.time() * 1_000_000)

payload = {
    "client_id": "client_123",
    "timestamp_micros": str(timestamp_micros),
    "events": [...]
}
```

### 7. Respect Consent

```python
payload = {
    "client_id": "client_123",
    "consent": {
        "ad_storage": "denied",
        "analytics_storage": "granted"
    },
    "events": [...]
}
```

## Limits

| Limit | Value |
|-------|-------|
| Events per request | 25 |
| Event name length | 40 characters |
| Parameter name length | 40 characters |
| Parameter value length | 100 characters |
| Parameters per event | 25 |
| User properties per request | 25 |
| Timestamp range | 3 days past, 72 hours future |

## Common Issues

### Events Not Appearing

**Causes:**
- Wrong Measurement ID
- Invalid API secret
- Validation errors
- Consent blocking

**Solutions:**
1. Validate with debug endpoint
2. Verify credentials
3. Check consent parameters

### Duplicate Events

**Causes:**
- Same request sent multiple times
- Missing deduplication logic

**Solutions:**
1. Implement idempotency
2. Track sent events
3. Use unique transaction IDs

### Missing User Association

**Cause:** Different client_id values

**Solution:** Store and reuse client_id from frontend

## Quick Reference

### 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 parameters per event
- 25 user properties per request

### Validation

- Send to debug endpoint
- Empty response = valid
- Check validationMessages array

Files in this skill

  • README.md1 KB
  • skill.md11.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.