๐ค Connect LinkedIn | ๐ฅ๏ธ Website AAWnu | ๐ซ Contact
PHP (Laravel) | JS/TS (Vue3, React[-native], Svelte[-kit]) | GOlang
Linux, Ubuntu | NodeJS | SQL (MariaDB)
PHP Wrapper for Google Analytics 4 with Server Side Tracking
License: The Unlicense
๐ค Connect LinkedIn | ๐ฅ๏ธ Website AAWnu | ๐ซ Contact
PHP (Laravel) | JS/TS (Vue3, React[-native], Svelte[-kit]) | GOlang
Linux, Ubuntu | NodeJS | SQL (MariaDB)
I tried posting a pageview, and the code worked without a glitch, but the usage is not reported or shown in the analytics dashboard. Am I doing something wrong?
include_once(__DIR__ . '/vendor/autoload.php');
use AlexWestergaard\PhpGa4\Analytics;
use AlexWestergaard\PhpGa4\Event\PageView;
$clientId = $_COOKIE['_ga'] ?? $_COOKIE['_gid'] ?? $_COOKIE['PHPSESSID'] ?? null;
if(isset($_COOKIE['_ga'])) {
$gaCookie = $_COOKIE['_ga'];
$clientID = explode('.', $gaCookie)[2];
}
$event = PageView::new()
->setLanguage('en')
->setScreenResolution('1024x768')
->setPageLocation('/home')
->setPageTitle('Home');
// GA4 Initialize
$analytics = Analytics::new ('G-xxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxx')
->setClientId($clientId)
->setTimestampMicros(time())
->addEvent($event)
->post();
If I send post without and do not provide user_id the script fails with the error:
Typed property AlexWestergaard\PhpGa4\Analytics::$user_id must not be accessed before initialization
How to reproduce:
$client->setClientId($data->client_id)
->setTimestampMicros($data->timestamp)
->addEvent($event)
->post();
Because property $user_id does not have a default value and is not set in the constructor.
But it works if add ->setUserId('') like:
$client->setClientId($data->client_id)
->setTimestampMicros($data->timestamp)
->addEvent($event)
->setUserId('')
->post();
Environment: PHP 8.3.0
Hi again Alex,
What is the rationale for Analytics::new('G-XXXXXX', 'eMVPMEcTbaI1iuWtrPw', true)
instead of new Analytics('G-XXXXXX', 'eMVPMEcTbaI1iuWtrPw', true)
?
Transform GA4Exception
to handle stacking on its own until being thrown; avoid having to pass it between classes when throwing is stalled until right before returning/exiting.
This should also make it simpler to use GA4Exception
when extending the base Model
class for custom event types.
Hi there,
I'm trying to use your package to record GA4 backend events and I'm not having much luck. I'm using Laravel 8 with php 8.1.
The code seems to execute (exception code does not fire), however the events are not appearing, specifically add_to_cart. Here is my code...
`
$measurementId = env('GA4_MEASUREMENT_ID');
$ga4ApiSecret = env('GA4_API_KEY');
$clientID = null;
if(isset($_COOKIE['_ga'])) {
$gaCookie = $_COOKIE['_ga'];
$clientID = explode('.', $gaCookie)[2];
}
try {
$events = Converter::parseEvents($event);
Analytics::new($measurementId, $ga4ApiSecret)
->setClientId($clientID)
->addEvent(...$events)
->post();
} catch (Exception\Ga4Exception $exception) {
// Handle exception
Log::alert('GA4 Event failed');
Log::alert($exception);
Log::alert($event);
}
`
My event looks like this...
array ( 'add_to_cart' => array ( 'currency' => 'AUD', 'value' => 38, 'items' => array ( 0 => array ( 'item_id' => 29, 'item_name' => '500g Musk Scrolls', 'price' => 38, 'quantity' => 1, ), ), ), )
The GA4 credentials and event data appear to be fine as I have recorded the event with another package but I like the way this package calls are made and it better fits my application.
Can you suggest how I can debug the problem? Many thanks
Require this codebase and extend the Model\Events class with self-defined event name and parameters.
In your experience, what happens if:
In which country will the purchase take place? The country of the user's IP address or the country of your server's IP address?
I would like to add arraycreation of events and items, where it is currently done through chained events only.
Currently:
use AlexWestergaard\PhpGa4\Event;
$event = Event\ViewCart::new()
->setCurrency('EUR')
->setValue(10.00);
I would like to also allow:
use AlexWestergaard\PhpGa4\Event;
$event = Event\ViewCart::fromArray([
'currency' => 'DKK', // eq ViewCart::$currency
'value' => 10.00', // eq ViewCart::$value
]);
It should also have proper validation for sub-model imports, so that ViewCart::addItem(Item $item)
would be triggered on <items=>Object|Array>
either by executing addItem
if object or import through item::fromArray()->toArray()
if Array.
the purpose of this should be the ability to build larger datasets and then import as array post-process rather than in-process.
I think there might be an issue with item_category
Item.php
public function addItemCategory(string $category)
{
$this->item_category[] = $category;
return $this;
}
I'm adding a category name like this
$item->addItemCategory( $category->name );
But then I get a validation error
jsonBody: {"non_personalized_ads":false,"client_id":"GA1.1123123123","events":[{"name":"view_item","params":{"currency":"GBP","value":2.6000000000000001,"items":[{"item_id":"443","item_name":"Complete Food Meal","currency":"GBP","item_category":["Food"],"price":2.6000000000000001,"quantity":1}]}}]}
Formatted jsonBody
{
"non_personalized_ads": false,
"client_id": "GA1.1123123123",
"events": [
{
"name": "view_item",
"params": {
"currency": "GBP",
"value": 2.6,
"items": [
{
"item_id": "443",
"item_name": "Complete Food Meal",
"currency": "GBP",
"item_category": [
"Food"
],
"price": 2.6,
"quantity": 1
}
]
}
}
]
}
Response code: 200
URL: https://www.google-analytics.com/debug/mp/collect?measurement_id=G-123&api_secret=XYZ
PHP Fatal error
Uncaught AlexWestergaard\PhpGa4\Exception\Ga4Exception: Validation Message > VALUE_INVALID [events.params.items]: Item param [item_category] has unsupported value. Value [list_value { values { string_value: "Food" } }] is unsupported list value. in /vendor/alexwestergaard/php-ga4/src/Exception/Ga4Exception.php:77
According to https://developers.google.com/analytics/devguides/collection/ga4/ecommerce?client_type=gtag#view_item_details
item_category should be a string and it allows to add up to 5 indexed item_categoryINDEX params
item_category: "Apparel",
item_category2: "Adult",
item_category3: "Shirts",
item_category4: "Crew",
item_category5: "Short sleeve",
I'm happy to update the code to work properly.
Thanks
Michal
I have found this in the google doc:
In order for an event to be valid, it must have a client_id that has already been used to send an event from gtag.js. You will need to capture this ID client-side and include it in your call to the Measurement Protocol. In send an event to your property, we use "client_id" as the client_id. You will need to replace this with a real client_id that comes from gtag.js.
Does your practical experience corroborate the quote or not?
If affirmative, I think it should be added to the doc.
I'm adding the stackoverflow question that made me think about this if you're interested https://stackoverflow.com/questions/69105735/google-analytics-4-measurement-protocol-api-used-without-gtag-js-or-firebase
I implemented tracking on a new property that tracks servers ONLY.
I see the pageviews correctly, but I don't see the users.
It's as if the events were not launched by users and therefore I can't understand their behavior, they all seem to be unconnected events.
I call the library and set setClientId to a unique value for each user.
Am I doing something wrong or is it not possible to have the concept of user by tracking only servers?
Need to update timestamp function in Analytics to match microtime 1.0e6 instead og 1.0e3 for Analytics to parse correctly.
Studying the PageView request made by GTAG in JavaScript it seems that parameter names are the same as V1 but with limited parameter scope.
https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
GET Parameters
v: 2
tid: G-XXXXX
gtm: 2oe7d0
_p: 1486226803
_z: ccd.v9B
cid: 00000.000000
ul: en-us
sr: 1920x1080
sid: 1657899578
sct: 3
seg: 1
dl: http%3A%2F%2F127.0.0.1%2F
dr: http%3A%2F%2F127.0.0.1%2F
dt: Chttr.link
_s: 1
Body Parameters
en=page_view&_ee=1
en=scroll&epn.percent_scrolled=90&_et=8
php-ga4/src/Exception/Ga4Exception.php
Line 37 in 3726d8f
I have finally found some reference documentation for the default events triggered by GA.js/GTAG.js and these should be implemented in this SST library to allow full sst-tracking.
https://developers.google.com/analytics/devguides/collection/ga4/reference/config
https://developers.google.com/analytics/devguides/collection/ga4/views?client_type=gtag
https://support.google.com/analytics/answer/9216061
https://support.google.com/analytics/answer/9143382
https://support.google.com/analytics/answer/9234069
In GA4 documentation there are two types of Refund - partial and full.
When I use event for Full refund, I need to set Items, but only transaction_id should be required. Items (selected) are required for partial refund.
The page_view
event is not officially supported by measurement protocol, maybe that should be reflected in the README.
Official support for PHP 7 will soon end. Updating the supported versions of this library will provide better options for type checking and stricter data control.
composer 1.0.*
composer ^1.1
This is a really nice library, thank you for building it. One thing I noticed is I couldn't find a way to enable debug_mode in events (not to be confused with the debug url).
This is supposed to allow measurement protocol events to show up in the "Debug View" in the Admin Console, making it easier to see in real-time if the right stuff is getting into Analytics.
If this is somehow supported and I just missed it please let me know. Otherwise it would be a cool setting to see added.
Make sure that codebase can be required with composer and used without issues.
Events should be sent in chunks without affecting User Properties or Analytics data.
Ideal practice would be iterating the post events in chunks before returning exceptions as it is impossible to validate everything before posting.
In order to give developers more freedom of how they want functionality to work inside each model, the type checks should depend on method access with stronger data validation rather than expect base functionality to not be overwritten.
I've been trying without success to get the debug mode working, in order to view events as soon as they are generated in debugView
(I have some events that google says are not correct and I would like to figure out why)
https://analytics.google.com/analytics/web/#/a62992619p355170503/admin/debugview/overview
Do you know how to do it? I will be happy to submit a PR for the readme as I believe it will be useful for others.
Here's my sample code:
$clientId = $_COOKIE['_ga'] ?? $_COOKIE['_gid'] ?? null;
if (!$clientId) {
throw new Exception('GA cookie not set');
}
$debug = true;
$analytics = Analytics::new($trackingId, $apiSecret, $debug)
->setClientId($clientId)
->setTimestampMicros(time());
$price = 1;
$transactionId = strtoupper(bin2hex(random_bytes(10)));
$purchase = Event\Purchase::new()
->setCurrency('USD')
->setValue($price)
->setTransactionId($transactionId);
$products = [
[
'name' => 'ball',
'amount' => 5.00,
], [
'name' => 'pen',
'amount' => 5.00,
],
];
foreach ($products as $product) {
$item = Item::new()
->setItemName($product['name'])
->setQuantity(1)
->setPrice($product['amount']);
$purchase->addItem($item);
}
$analytics->addEvent($purchase);
$analytics->post();
Hi, is this how to do a begin checkout in the backend?
use AlexWestergaard\PhpGa4\Exception;
use AlexWestergaard\PhpGa4\Analytics;
use AlexWestergaard\PhpGa4\Event\BeginCheckout;
use AlexWestergaard\PhpGa4\Item;
try {
// If gtag.js, this can be the _ga or _gid cookie
// This can be any kind of session identifier
$session = $_COOKIE['_ga'] ?? $_COOKIE['_gid'] ?? $_COOKIE['PHPSESSID'];
$analytics = Analytics::new( 'G-XXXXXXXX','xYzzX_xYzzXzxyZxX')
->setClientId($session);
$analytics->addEvent(new BeginCheckout);
$analytics->setCurrency('usd');
$analytics->setValue('60.00');
$analytics->addItem([
'item_id' => 'bla bla',
'currency'=> 'USD',
'price' =>'60.00',
'quantity'=> 1
]);
$analytics->post();
} catch (Exception\Ga4Exception $exception) {
// Handle exception
if (YII_DEBUG) dd($exception);
Yii::error($exception);
}
i'm getting this error
AlexWestergaard\PhpGa4\Exception\Ga4IOException#1
(
[*:message] => 'Missing required parameter: items'
.....
.....
how do i fix this? Thank you.
I never get the _gid
cookie, does it still exist? If not, we should remove it from the readme
$session = $_COOKIE['_ga'] ?? $_COOKIE['_gid'] ?? $_COOKIE['PHPSESSID'];
Please add support for the recently released PHP 8.3.
Thanks.
If you follow the code then you will see there is 3 layers.
Analytics[ Events[ Items ] ] ]
Add src/Item.php
to your src/Event/BeginCheckout.php
event, then add the event to src/Analytics.php
.
You should not be able to
addItem
onAnalytics
, if this is doable then I will fix it later.
Originally posted by @aawnu in #55 (comment)
sorry i really dont understand what you mean. how do i add items to my events?
in your begincheckout class you do have this
public function addItem(Facade\Type\ItemType $item)
{
$this->items[] = $item->toArray();
return $this;
}
and i did add it.
$analytics->addItem([
'item_id' => 'bla bla',
'currency'=> 'USD',
'price' =>'60.00',
'quantity'=> 1
]);
HI,
have you ever managed to track on GA4 without using the gtag.js part to get user identifiers?
I tried, but I can't see the complete data on GA4, perhaps because the session_start event cannot be sent via API.
I would like to do completely server tracking, do you think it's possible in some way?
Hello, first of all, thank you for the great library.
I've a few questions about the user properties, is anyone able to help me?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.