Skip to content

Setting GA Cookies Server Side with PHP – ITP Workaround

David Vallejo

Yeah, I know, this has been done before by others, but since I had this piece of code around, I decided to publish it.

It’s not going to be usual, method since we’ll be relying on sending a duplicate hit to our tracking subdomain. That way we’ll be able to have our stuff tracked server-side in a secondary dimension while those hits will take care of setting the cookie expiring time on the main. isn’t it cool?

What we’ll need

  1. A subdomain for our domain, for example ( it’s better if we don’t make it that obvious )
  2. A customTask added in our tags, in order to send a hit copy to our subdomain.
  3. We’ll need some PHP code that will receive the hit details ( payload, cookie name, etc ), will have the job of writting the cookie back and also will be taking care of the CORS headers.

Working Flow

2. Let’s Start: Setting up our customTask

The first thing we need to do is to create a custom Variable with our customTask code. You can find the code below.

Copy the code

function() {
    var gaProxyEndpoint = '';
    return function(customTaskModel) {
        customTaskModel.set('cookieUpdate', false);
        var originalSendHitTask = customTaskModel.get('sendHitTask');
        customTaskModel.set('sendHitTask', function(model) {
            try {
                var gaCookieName = model.get('cookieName');
                var base64encodedPayload = btoa(model.get('hitPayload')+'&ckn='+gaCookieName);             
                var xhr = new XMLHttpRequest;
                xhr.withCredentials = true;
      "POST", gaProxyEndpoint, false);
            } catch (err) {

After we have the variable, we’ll need to tell the tags to use it a customTask, if you’re already using a customTask you’ll need to sort it out yourself mergin this piece of code with your current code.

As you may see on the following screenshot, there’s an extra field set. It’s name “cookieUpdate”, and we’ll need that set to false because otherways analytics.js will keep updating the cookie expire time after we did the same, therefore the cookie time will be reset to 7 days on Safari.

3. Let’s finish: Setting up the PHP files

We’ll need to upload the php files to our subdomain


We are all set now!

After we publish everything, for each hit send via GTM, a request will be also be sent to our endpoint, which will take care of everything so cookies are written from the server.

There’re some tweaks you may want to add to the customTask, for example you may want to check if it’s a Safari browser, and just run the custom task if the check is true. Just give a try to “Detect Safari JavaScript” search on Google 🙂


As you may have read, we could also set the PHP file to send a copy of the hits. For enabling this feature, just open the index.php and uncomment the following line

// private $propertyId = 'UA-XXXXXXX-UU';

The good thing about this is that the payload goes encoded using BASE64, so it won’t be detectable by adblockers at all. So you may end finding some better sessions info on the secondary property?.

ok, I know, most adblockers will likely block the analytics.js file so, none of this will make a difference, but, even if it’s not a good idea you may plan to server the file locally with a different name, do you follow me? 🙂

If someone gives it a try just let me know!