Package
Development
composer require alexwestergaard/php-ga4
European Union have noticed that default setup of Google Analytics does not comply with GDPR as data is sent unrestricted to an american service possibly outside of Europe.
This includes the use of
gtag.js
/gtm.js
as JavaScript pushes the request from visitors device including their IP-Address. Server Side Tracking, however, does only send information specified inside the body and about your server.Relying solely on Google Analytics 4 Events - that is not pushed through the
gtag.js
/gtm.js
script - can be scraped of GDPR-related information.
- Source: Europe, GDPR, Schrems II
- https://support.google.com/analytics/answer/9019185?hl=en
To get started, you will need two things:
- a data stream can be created under
Admin
>Data Streams
, get its measurement id eg.G-XXXXXXXX
- an API key to send events to the data stream
Admin
>Data Streams
> Select data stream >Measurement Protocol API secrets
>Create
use AlexWestergaard\PhpGa4\Analytics;
$analytics = Analytics::new('G-XXXXXXXX', 'xYzzX_xYzzXzxyZxX');
This is a list of prebuilt events as shown in the documentation.
This library is built for backend server side tracking, but you will probably trigger most events through frontend with Javascript or Websockets. There will be 2 examples, one as pure backend for logged/queued events and one for frontend to backend communication.
use AlexWestergaard\PhpGa4\Exception;
use AlexWestergaard\PhpGa4\Analytics;
use AlexWestergaard\PhpGa4\Event;
use AlexWestergaard\PhpGa4\Item;
// require vendor/autoload.php
// 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'];
// Render events grouped on time
foreach ($groups as $time => $data) {
try {
$analytics = Analytics::new($measurementId, $apiSecret)
->setClientId($session)
->setTimestampMicros($time);
// load logged in user/visitor
if ($auth) {
// This can be any kind of identifier, readable is easier for you
// Just be wary not to use GDPR sensitive information
$analytics->setUserId($auth->id);
}
$analytics->addUserParameter(...$data['userParameters']);
$analytics->addEvent(...$data['events']);
$analytics->post();
} catch (Exception\Ga4Exception $exception) {
// Handle exception
// Exceptions might be stacked, check: $exception->getPrevious();
}
}
axios.post('/api/ga4', [
{
addToCart: {
currency: 'EUR',
value: 13.37,
items: [
{
'item_id': 1,
'item_name': 'Cup',
'price': 13.37,
'quantity': 1
}
]
}
}
])
use AlexWestergaard\PhpGa4\Helper\ConvertHelper;
use AlexWestergaard\PhpGa4\Exception;
use AlexWestergaard\PhpGa4\Analytics;
use AlexWestergaard\PhpGa4\Event;
// require vendor/autoload.php
try {
$events = ConvertHelper::parseEvents($_POST);
Analytics::new($measurementId, $apiSecret)
->addEvent(...$events)
->post();
} catch (Exception\Ga4Exception $exception) {
// Handle exception
// Exceptions might be stacked, check: $exception->getPrevious();
}
You can build your own custom events. All you need is to implement and fullfill the AlexWestergaard\PhpGa4\Facade\Type\Event
facade/interface. If you want ease of life features, then you can extend your event from AlexWestergaard\PhpGa4\Helper\AbstractEvent
and overwrite as you see fit.
// EventHelper implements AlexWestergaard\PhpGa4\Facade\Type\EventType
class ExampleEvent extends AlexWestergaard\PhpGa4\Helper\EventHelper
{
// variables should be nullable as unset() will set variable as null
protected null|mixed $my_variable;
protected null|mixed $my_required_variable;
// Arrays should always be instanciated empty
protected array $my_array = [];
public function getName(): string
{
return 'example_event';
}
public function getParams(): array
{
return [
'my_variable',
'my_array',
];
}
public function getRequiredParams(): array
{
return [
'my_required_variable',
];
}
public function setMyVariable(string $value)
{
$this->my_variable = $value;
return $this; // Allows chained events
}
public function setMyRequiredVariable(string $value)
{
$this->my_required_variable = $value;
return $this; // Allows chained events
}
}