A few days ago I was looking at the tracking for a hybrid iOS/Android app where the Apps appended a query string to the URLs in app. Given this, I had two versions of each URL in Google Analytics, looking something like this:
- www.domain.com/awesome-post/
- www.domain.com/awesome-post/?device=app
The first one is the URL that is being used on the desktop version of the site, no matter of you are browsing with a laptop, mobile phone or tablet. The latter one is the URL being used if you open the link from within the app on your phone.
An easier way of doing this is probably using rewrite filters in Google Analytics, but since I want to do most things in Google Tag Manager this is how I solved the issue, taking into account that we don’t want to get rid of the query string in its entirety but only that part.
If we e.g. would have another custom parameter attached to the URL we don’t want that part removed.
www.domain.com/awesome-post/?promo=true&device=app
The only part we want to have removed in this case is ‘&device=app‘, right?
The magic sauce in GTM
So, in order to make this work we are going to use a few Built-In Variables and a Custom Javascript. The Built-In Variables you are going to need is the basic Page URL and Page Path.
We are also going to use a custom URL variable that I named {{URL – Query Parameters}} that look like this:

That is, we’re choosing the Type: URL, and the change the Variable to Query so that we get everything after the ‘?’ in the URL inside that variable. Note that this variable will not include the ?. We’ll have to append that later on if needed, before sending the data into Google Analytics.
And this is the Custom Javascript we are going to use.
function() {
var url = {{ Page URL }};
var path = {{ Page Path }};
// Define regex to ONLY remove the ‘device’ parameter from query string
var queryString = {{ URL – Query Parameters }};
var res = queryString.replace(/&device(\=[^&]*)?(?=&|$)|^device(\=[^&]*)?(&|$)/, "");
if (url.indexOf("device = app") <= -1 && res.length == 0) {
return path;
} else { // Join path with remaining query parameters if any
if (res.length > 0) {
var cleanedPath = path + "?" + res;
} else {
// If no other query strings are present, don’t append ‘?’ to string
var cleanedPath = path;
}
return cleanedPath;
}
}
Let’s break this down, piece by piece, shall we?
var url = {{Page URL}};
var path = {{Page Path}};
var queryString = {{URL – Query Parameters}};
First of all, we are declaring the Variables we need throughout the code.
We begin by storing the entire Page URL inside ‘url‘ – we will use this basically only to check if the query string parameter we are looking for is being used or not. You could check just the query string, and not the entire URL. But this is me being lazy, and not rewriting the script for that demonstration.
var res = queryString.replace(/&device(\=[^&]*)?(?=&|$)|^device(\=[^&]*)?(&|$)/, "");
Next, we have a pretty odd looking piece of code, containing a regular expression we are using to replace a potential match.
We define the variable ‘res’ where we will store the result based on the queryString and the end result of the JavaScript replace. Basically it will look if the query string contains &device or device (the variable doesn’t contain the ‘?’, remember?) and the remove the parameter completely, but leaving the rest intact.
if (url.indexOf("device = app") <= -1 && res.length == 0) {
return path;
} else { // Join path with remaining query parameters if any
if (res.length > 0) {
var cleanedPath = path + "?" + res;
} else {
// If no other query strings are present, don’t append ‘?’ to string
var cleanedPath = path;
}
return cleanedPath;
}
}
The first part of the code above will check if the string device=app is not present, using the Javascript function indexOf();. If it contains the text, it will return the position within the string, otherwise it will return -1. So, we are checking if the device=app is not present, and if there are no other variables being used. That is, the variable res has to be of zero length.
If that us the case, just return the path as it is, since we don’t have to append any other variables. But if there are other variables, it’s going to get handled by the next part of the code.
In that case, we store the current path, add ‘?’ since it got removed prior, and the add the remaining queries and return the value.
Given this, we can now use a Tag inside Google Tag Manager that will take the value of this function and return it as the page parameter.
A bit tricky, and I had to try a lot of different scenarios to make sure it did fire when it should and that it didn’t fire when it shouldn’t. But then again, testing is fun and necessary.
Having this in place also means that I can use a Custom Dimension to separate App traffic from other traffic and sort accordingly in GA.