GA4 + GTM: Remove URL query params from all page data - google-tag-manager

How do I remove URL params from getting pushed to GA4 through GTM? I have tried many solutions but none seem to be working.
Which key in "Fields to Set" do I need to use so GTM replaces the url query param from all dimensions like page_path, page_location, path_referrer?

This article has been my life saver when dealing with URL params in GA4, but please use my experience and avoid the mistake of applying the script directly to page_location.
page_location is what I call a technical dimension that GA4 uses to sort referring websites according to its internal rules and do any other GA4 things. Remove URL params from page_location using GTM, and you'll stop seeing all channels, reliant on UTMs—so paid search, display, paid social, email etc (provided you use UTMs, of course). Don't forget: in this case, you remove the URL params in GTM before they get in GA, so if GTM strips params out, GA doesn't see them.
To illustrate my mistake, this is how my GA4 configuration tag in GTM looked like initially:
Bad idea. Don't touch page_location.
The best approach is to just create your own dimension which you would use to store 'clean' URLs, say, page_URI. The reason: you stop relying on GA built-in dimensions that (potentially) are prone to change and you create something of your own that you will have control over and can add to any event as a dimension.
Below is my version of the script in GTM, deployed as a Custom Javascript Variable:
function() {
var params = ['hash', 'email', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'gclid', 'fbclid', 'mc_cid', 'mc_eid', 'msclkid']; //Add URL params to be excluded from page URI
var a = document.createElement('a');
var param,
qps,
iop,
ioe,
i;
a.href = {{Page URL}};
if (a.search) {
qps = '&' + a.search.replace('?', '') + '&';
for (i = 0; i < params.length; i++) {
param = params[i];
iop = qps.indexOf('&' + param + '=');
if(iop > -1) {
ioe = qps.indexOf('&', iop + 1);
qps = qps.slice(0, iop) + qps.slice(ioe, qps.length);
}
}
a.search = qps.slice(1, qps.length - 1);
}
return a.href;
}
Two things to mention about the code:
List all params you want to strip out in the array params;
a.href = {{Page URL}} - the code makes use of GTM's built-in variable Page URL (hence double curly brackets) that captures the full URL (without hostname, though). If you feel fancy, you can replace it with plain JS.
So the code above now populates the GTM field/GA4 dimension page_URI in the main configuration tag and any other tags, where I think having a clean URI is useful:
I do realize that this approach uses up one GA4 dimension, but it's a price I'm willing to pay to have a clean URL in the absence of a better solution.

In the GA4 tag in GTM try to set page_location as Field to Set and a Custom JavaScript Variable as value with this definition:
function(){
return document.location.hostname + document.location.pathname;
}
i.e. (note: App+Web is old name of GA4):

You can also use the following JavaScript in the custom JavaScript variable instead of the custom JavaScript mentioned above.
In this custom JavaScript instead of creating a new anchor element, we simply are taking the full page URL and then using the JavaScript's in-built URL() method to convert it to a proper URL that can be programmatically managed and then manage it according to the need.
I'm sharing my script below:
Step 1
Create a custom JavaScript variable inside your GTM and add the following JavaScript code into it.
function() {
// Set the array with the list of query string you would like to remove being shown up in Google Analytics 4
var excuded_query_params = [
'add',
'the',
'query',
'strings',
'you',
'would',
'like',
'to',
'be',
'removed',
'from',
'GA4',
'analytics',
'report'
]
// Get the full Page URL from GTM in-build variables
var page_url_string = {{Page URL}}
// Convert the received URL from string format to URL format
var page_url = new URL( page_url_string )
var page_url_copy = new URL( page_url_string )
// Loop through the query parameters in the URL and if there is any query param which is in the excluded list,
// remove that from the full URL
page_url_copy.searchParams.forEach( function(param_value, param_name) {
if( excuded_query_params.includes( param_name ) ) {
page_url.searchParams.delete( param_name )
}
} )
// Return the final URL
return page_url.toString()
}
Please Note: as we are going to replace the value of page_location a default GA4 variable's data - it is highly recommended that you do not remove the utm_ query parameters from the URL as GA4 reports use that data internally and that may lead to report breaking. So, it's best that you do not remove query parameters like utm_souyrce, utm_campaign etc.
Step 2
Inside your GA4 Configuration Tag, click on Fields to Set and add a new field with the Field Name set as page_location and value set as this custom JavaScript variable.
Step 3
Now it's time to preview inside GTM and deeply.

Related

Fix Self referral issue in GA4 property

Our GA4 property in Google analytics is showing our own website as a referral source. Normaly, in ga3 property there is a filter where you can exclude sites like payment portals and such. In the new property this feature is not yet available.
We tried using the following script to workaround the problem
var ref = {{Referrer}};
// don't bother if there is no referrer
if (!ref) return ref;
var newref;
// place your external referrers here (domain names)
// adding 'foo.bar.com' matches 'www.foo.bar.com' too
var domains = [
// banks
'rabobank.nl', 'ing.nl', 'abnamro.nl', 'regiobank.nl', 'snsbank.nl',
'asnbank.nl', 'triodos.nl', 'vanlanschot.nl', 'knab.nl', 'bunq.com',
'frieslandbank.nl', 'snsreaal.nl', 'secure-ing.com',
// payment providers, cards, foreign banks
'mollie.nl', 'mollie.com', 'paypal.com', 'paypal.nl', 'adyen.com',
'multisafepay.com', 'visa.com', 'wlp-acs.com', 'belfius.be', 'payin3.nl',
'icscards.nl', 'arcot.com', 'securesuite.co.uk', 'hsbc.com.hk',
'cm-cic.com', 'pay.nl', 'redsys.es', 'tatrabanka.sk'
];
domains.forEach(function(x) {
// loop through domains,
if(ref.match(RegExp('^https?://([^.]+\.)?'+ x +'/')))
newref = x;
})
// return referrer, or the new one
return newref ?
'https://' + {{Page Hostname}} + '/excluded-referrer/' + newref
: ref
}
The script does not work though. Could you give me any new recommendation on how to solve this issue or tell me if the code might be wrong?
Thanks
Update: Google actually releases gradually a referral exclusion feature in GA4, which you can find here:https://support.google.com/analytics/answer/10327750?ck_subscriber_id=750579406
Thankfully this will help with this problem.

custom javascript cannot return client ID var google tag manager

I have tried to get the client ID with custom javascript but it cannot return the value. Below is the code is tried. Would like to seek help from all experts. Thanks.
function () {
return function () {
try {
var trackers = ga.getAll();
trackers.forEach(function(tracker) {
var cid = tracker.get('clientId');
tracker.set('dimension1', cid);
});
} catch (e) {}
}
}
It cannot return a normal client ID
Your custom variable returns a function, not a value (since the function is never actually executed).
A better way to get the clientId for each current tracker is to use a custom task in Google Analytics (tasks are basically individual steps in the tracker lifecycle, from checking if a client id exists to assemble the payload to actually sending the data). A task is a Javascript function that is added to the GA tag via the "set fields" configuration. Tasks have access to the tracker data model and can add, remove or modify values from the payload.
The only task you can use via GTM is the customTask, which as the name suggests, adds custom capabilities to the tracker.
If you create a custom javascript variable called e.g. "getClientId" with the following code:
function() {
// Modify customDimensionIndex to match the index number you want to send the data to
var customDimensionIndex = 5;
return function(model) {
model.set('dimension' + customDimensionIndex, model.get('clientId'));
}
}
then go to your GA settings tag, and in the "set field" configuration set the field name "customTask" with the variable as value, the clientId will be extracted from the data model and added to the payload as custom dimension.
Better than my explanation is Simo Ahavas GTM tip for setting the client id via custom tasks.

I am noticing double entry (cpc and organic) for the same user ? little confused

I'm noticing double entry in google analytics. I have multiple ocurrences where it looks like the user came from the CPC campaign (which always has a 0s session duration) but that very same user also has an entry for "organic" and all the activities are logged under that.
My site is not ranked organically for those keywords. Unless a so many users come to my site, leave, and google for my "brand name" on google and revisits, this doesn't make sense.
I'm a little confused. Here's the report:
preview from google analytics dashboard
Based on the additional information in your comment, that the sites is a Single Page Application (SPA), you are most likely facing the problem of 'Rogue Referral'.
If this is the case, what happens, is that you overwrite the location field in the Analytics hit, losing the original UTM parameters, whereas referral is still sent with the hit, so Analytics recognizes the second hit as a new traffic source. One of the solutions is to store the original page URL and send it as the location, while sending the actual visited URL in the page field.
A very good article on this topic with further tips, by Simo Ahava, is available for your help.
Also please note, that as you have mentioned, that the first hit shows 0 second time on page, you might need to check, whether the first visited page is sent twice. E.g. sending a hit on the traditional page load event, and sending a hit for the same page as a virtual page view.
I have come up with a solution to this problem in a Gatsby website (a SPA), by writing the main logic in the gatsby-browser.js file, inside the onRouteUpdate function.
You can use this solution in other contexts, but please note that the code needs to run at the first load of the page and at every route change.
If you want the solution to work in browsers that do not support URLSearchParams I think you can easily find a polyfill.
Function to retrieve the parameters
// return the whole parameters only if at least one of the desired parameters exists
const retrieveParams = () => {
let storedParams;
if ('URLSearchParams' in window) {
// Browser supports URLSearchParams
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
const requestedParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'gclid'];
const hasRequestedParams = requestedParams.some((param) => {
// true if it exists
return !!params.get(param);
});
if (hasRequestedParams) {
storedParams = params;
}
}
return storedParams;
}
Create the full URL
// look at existing parameters (from previous page navigations) or retrieve new ones
const storedParams = window.storedParams || retrieveParams();
let storedParamsUrl;
if (storedParams) {
// update window value
window.storedParams = storedParams;
// create the url
const urlWithoutParams = document.location.protocol + '//' + document.location.hostname + document.location.pathname;
storedParamsUrl = `${urlWithoutParams}?${storedParams}`;
}
Send the value to analytics (using gtag)
// gtag
gtag('config', 'YOUR_GA_ID', {
// ... other parameters
page_location: storedParamsUrl ?? window.location.href
});
or
gtag('event', 'page_view', {
// ... other parameters
page_location: storedParamsUrl ?? window.location.href,
send_to: 'YOUR_GA_ID'
})

Google analytics - event hits don't work after sendHitTask

Just started integration of Salesforce Community with Universal Google Analytics (beginner in both).
Adding GA integration code in tag.
Downloaded GA debugger for Chrome.
Browser: Chrome.
Here is code in the tag:
<script>
(function(i,s,o,g,r,a,m)
{i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||
[]).push(arguments)},i[r].l=1*new Date
();a=s.createElement(o),m=s.getElementsByTagName(o)
[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})
(window,document,'script','https://www.google-
analytics.com/analytics_debug.js','ga');
window.ga_debug = {trace: true};
ga('create', 'UA-xxxxxxxxx-x', 'auto');
ga('send', 'pageview');
ga(function(tracker) {
tracker.set('sendHitTask', function(model) {
var hitPayload = model.get ( 'hitPayload' );
console.log ( 'models payload: ' + hitPayload );
// need this section to get user id value to send to dimension
//ga('set', 'dimension3', tracker.get('userId'));
});
});
</script>
Later in the code we make calls to track events.
After I've added
"ga(function(tracker) {" code section
those calls to track events do Not work any more (used to work).
What is wrong with the code above?
When you set the sendHitTask for the tracker, you're overriding it; that is, you're removing the normal task that sends data to Google Analytics and replacing it with your own. So, after you do this, any hits you track won't be sent to GA.
Instead, before you set the sendHitTask, you need to get the existing one and execute that function first in your new sendHitTask function.
From documentation for adding to a task, some code to do this follows. Before your tracker.set call, you need to add:
// Grab a reference to the default sendHitTask function.
var originalSendHitTask = tracker.get('sendHitTask');
Then, in your function that you're assigning to sendHitTask, you'll need to call that function:
// Send the normal request to Google Analytics
originalSendHitTask(model);
You have crippled your sendHitTask, because the method you provided to override it does not do any sending - you have replaced it with a function that logs something to the console and nothing else.
If you look at the example in the documentation you see that there they stored the original sendHitTask in a variable and called within the custom function.
Also you cannot use the ga object within the task, you access the properties of your tracker via the model that is passed in to the task.
So you would need something like
ga(function(tracker) {
// Grab a reference to the default sendHitTask function.
var originalSendHitTask = tracker.get('sendHitTask');
tracker.set('sendHitTask', function(model) {
model.set('dimension3',model.get('userId'));
originalSendHitTask(model);
});
});
Also you might consider to use the customTask to add custom behavior, although it will give the same result.

How to get statistics of where visitors come from via URL params

There are many QR codes that contains URL of website such as:(it just demos link)
http://www.popupstore.com/index.php?qrcode_type=magazine&location=Singapore
http://www.popupstore.com/index.php?qrcode_type=banner&location=Vietnam
I need a way can summary to know that where customer come from (nearly same as source/channel in Google Analytics):
Type: Mazazine, banner, etc.
Location: Vietnam, Singapore, etc.
Can anyone help me please :)
You could create two Custom Dimensions, each for Type and another for Country
As per your need define the appropriate Scope of the dimension, a Hit level or Session level scope would be appropriate.
You need to push custom dimensions into Google Analytics i.e. additonal JS code in your site.
ga('send', 'pageview', {
'dimension1': 'Magzine',
'dimension2': 'Singapore'
});
How this works
User scans the code and visits the store
Site has a JS code snippet that would get the query parameters from the URL and sets a custom dimension for each parameter
Setting the custom dimension would let Google Analytics know the value of the Type and Country
It is your JS code that tells Google Analytics what value to take for custom dimension. Google Analytics would not know that the value came from the URL.
To get a query parameter value via javascript you can refer to this answer, If you take the function provided there by Jan Turon (head over and give him an upvote of this helps you):
function getJsonFromUrl() {
var query = location.search.substr(1);
var result = {};
query.split("&").forEach(function(part) {
var item = part.split("=");
result[item[0]] = decodeURIComponent(item[1]);
});
return result;
}
You can use this to dynamically set the dimensions based on the url. You first call the function to return an JSON object that has the key/value pairs from the query parameters, then you insert the needed values to set the dimensions:
result = getJsonFromUrl();
ga('send', 'pageview', {
'dimension1': result.qrcode_type,
'dimension2': result.location
});

Resources