I’m trying to send a purchase event to Google Analytics 4 using the Measurement Protocol from my Laravel backend. I’m not using gtag.js or Firebase — only server-side requests.
Here’s what I’m doing:
- On the frontend, I extract the client_id from the _ga cookie using JavaScript and send it to the backend (e.g., via Ajax or form data).
- I store that
client_idin the database (associated with the user or session). - Later, when the user completes a purchase (which could be minutes or even days after the initial visit), I use the previously saved
client_idto send apurchaseevent via Measurement Protocol.
Here’s a simplified version of the code I use:
public function gtmPaidOrder() {
$clientId = $this->client_id; // previously saved from frontend _ga cookie
if (!$clientId) return false;
$measurement_id = 'G-XXXXXXX';
$api_secret = MY_SECRET;
$payload = [
'client_id' => $clientId,
'events' => [
[
'name' => 'purchase',
'params' => [
'transaction_id' => $this->id,
'value' => $this->getTotalPrice(),
'currency' => $this->currency,
'items' => [
[
'item_id' => '123',
'item_name' => 'Test Product',
'price' => 20,
'quantity' => 1
]
],
'debug_mode' => true
]
]
]
];
$url = "https://www.google-analytics.com/debug/mp/collect?measurement_id={$measurement_id}&api_secret={$api_secret}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Log::info('GA4 MP response', ['response' => $response]);
}
Google returns a 200 OK response with the following body:
{
"validationMessages": [ ]
}
All other events sent from the frontend appear in DebugView, but this event does not. Why?