Google Analytics 4 - How to fix events not being tracked when sending User ID via Measurement Protocol

Back to Blog
Google Analytics 4 - How to fix events not being tracked when sending User ID via Measurement Protocol

Google has been hard at work making changes to their platforms, particularly when it comes to tracking, user consent and merchant acknowledgement of their services & data usage. Recently, users across all platforms have been reporting problems with the Measurement Protocol, an API that can be used to send data to Google Analytics server-side, which our Google Analytics 4 PRO extension can make use of. Particularly, users are reporting that events sent to Google Analytics 4 with Measurement Protocol simply aren't being recorded.

There are numerous threads on the topic, ranging from Stack Exchange, the Google Community and Google's own Issue Tracker, however, there doesn't seem to be an answer as to why this may be happening. It looks like the problem started around the beginning of 2024, and continues to this day, at the time of writing this post. Since our Google Analytics 4 PRO extension utilizes Measurement Protocol, we've had a few reports from our own users as well, but there was no clear answer to give, as it just looked like some Google Analytics properties recorded events just fine, while some simply would not when using Measurement Protocol.

How we discovered the root cause of the issue

The initial observations related to the User ID

As soon as we started getting reports from users, we started our research and internal investigations into the lack of tracking, and, in standard Magento 2 fashion, started our attempts to reproduce the same behavior. At the beginning, it was proving impossible to reproduce, because the Google Anaytics instances we tested on all recorded events just fine, be it via Client-Side Tracking or Measurement Protocol. At one point, however, seemingly through a stroke of luck, one of the Analytics properties we were testing on began exhibiting lack of event recording via Measurement Protocol, on one condition: it only happened when the user being tracked was signed in to their account. Here's what we knew thus far:

  • Client-side tracking via tags worked without any issues in all circumstances
  • Measurement Protocol tracking stopped working when the user was signed in

Measurement Protocol uses JSON payload data to send events to Google's API, and the only difference between an event sent for a user that's signed in, as opposed to one that's not, is that when a user is signed in, Magento assigns that user an ID. which our extension then includes into the payload data as a user_id, property. This was the only difference, and surely enough, disabling the User ID setting in the extension's configuration options ensured events were once again registered in Google Analytics. If you're unsure about what the User ID is and how it differs from Client ID, you can read more about them here: How to differentiate between Google Analytics 4 Client ID and User ID?

Google's API validates payload data and returns an error when the data is formatted incorrectly, or when a property that's not accepted is sent, however, even events sent with the user_id property were properly validated, and even made it into Google Analytics 4's Debug View, which ruled out corrupt data. To take this one step further, even using the Google Analytics Event Builder Tool to send custom built and validated events would result in the event not being registered when sending the user_id as well.

At this point, the only solution was to stop sending the user_id property altogether, however, providing the User ID to Google Analytics is useful as it allows for stitching together sessions to provide more accurate attribution insights, so we were keen to find out exactly what caused the lack of processing for specific Analytics Properties.

Digging deeper to find the Google Analytics property setting responsible

Thus began the part where we took a fresh Google Analytics property (which recorded events just fine) and compared every single setting, side by side, to the testing property that exhibited the issues. The process was quite tedious, as there are a lot of settings, however, we managed to reach a section that's quite deep into the property called Data Collection, which can be found in Settings → Data Collection and Modification → Data Collection.

This is what the section looks like on the Google Analytics 4 property that would not process Measurement Protocol events with the user_id property:

Google Analytics 4 Property - User Data Collection Acknowledged

This is what the section looks like on a fresh Google Analytics 4 property:

Google Analytics 4 - User Data Collection Unacknowledged

Google may change this in the future, but at the time of writing this post, when you first interact with this section, there's no toggle for you to set, just a prompt allowing you to select an Industry, and a Save button. Once you click Save, you've Acknowledeged the User Provided Data Collection Policy. There's no way to unacknowledge this policy, and once you've done so, sending the user_id with your Measurement Protocol events will cause Google Analytics to discard those events.

As you can see in the second image above, once you acknowledge, a toggle becomes available under User-provided data collection, however, this toggle has no bearing on whether or not the event is registered, so toggling it off won't resolve the issue at hand. Given the actual solution (which is probably more workaround, as this is very likely either a bug in the Measurement Protocol, or a requirement that Google has failed, as of yet, to shed light on) that we'll be looking at a bit further down the post, this toggle likely should fix the issue when set to the Off position, but it doesn't.

Applying and testing the solution

Exploring Google's Documentation on Measurement Protocol, we can see that there's a possibility to send User Provided Data alongside events, however, at the time of writing this post, nowhere in the documentation have we found that, when sending the user_id property, one must also send a user_data (User Provided Data) object in the payload. Conversely, the documentation does state that, if you send user_data, you must also send user_id, which does indeed make sense.

It looks like the opposite is true, however, and after testing with sending an empty user_data object in the event payload, the event was then registered correclty in Google Analytics. It's impossible to determine, at this point, whether this is intentional by Google (the chances are that it's not), however, this points to the solution, at the time of writing this post, being one of the following:

  1. Not sending the user_id property at all. If you're using our Google Analytics 4 PRO extension, this is easily achievable by disabling the User ID setting in the configuration.
  2. Modifying your event payload to include the user_data property (an object), which can be empty.

Here's an example of a JSON payload for a purchase event containing an empty user_data object:

                  "item_name":"Wayfarer Messenger Bag",
                  "affiliation":"Main Website - Main Website Store - Default Store View",
                  "item_stock_status":"In stock",

Either of these options should ensure, for the time being, that events are properly registered in Google Analytics when using the Measurement Protocol functionality. If you're using our Google Analytics 4 PRO extension, we'll be looking into introducing solution number 2 into the extension, in a version following 1.14.1, which is the current latest release, however, for the time being, you can use solution number 1.

Alternatively, you're able to customize the extension and add the user_data object to the event payload, which is defined in app/code/WeltPixel/GA4/Model/ServerSide/Events, with a PHP file corresponding to each event. You'll need to add the object to each one of the events, and it's recommended you do so inside the method that sets the User ID, something like:

public function setUserId($userId)
    $this->payloadData['user_id'] = (string)$userId;
    $this->payloadData['user_data'] = '{}';
    $this->payloadData['user_data'] = (object)[];
    return $this;

Related Products