In this modern day of work, if you still rely on using IP to filter or track internal traffic in your analytics stacks, there is a high probability that you are not doing it right.
Yes, tools like Google Analytics, Hotjar, Fullstory, Microsoft Clarity, Yandex Metric, etc. have internal traffic filtering capabilities that rely solely on the user IPs, which seems easy, but in recent years has proven that it doesn’t work for the following scenarios;
- Remote and large teams
- Team members that visit your website using public wifi (cafes, restaurants, gardens, etc.)
- A team member who might visit your website while on vacation
- Team members with dynamic IP address
- Websites where internal traffic doesn’t need to be filtered out but should be labelled.
The non-IP methodology I am about to share in this article relies on leveraging the power of Google Tag Manager and having a strong internally communicated measurement culture.
Graphical Design Of How IP-Based Filtering Works
Here is a graphical illustration which breaks down how all analytics stacks that can filter traffic based on IPs work.
- A user visits your website XYZ.com
- Your website content and tag management system housing all your tags loads
- The analytics tag sends the user data to your analytics tool
- The analytics tool checks if your IP matches the list of IPs to be filtered out
- If yes, your traffic gets excluded, and if no, your traffic gets retained.
Graphical Design Of How GTM-Based Filtering Works
For the non-IP approach, here is a graphical illustration of how the system works.
- User A visits your business/client website XYZ.com.
- Your website content and tag management system housing all your tags loads
- GTM checks if the user fits into the sets of non-IP rules that you use to check if the traffic is from your teammates or not.
- Based on your needs, the internal traffic rule will route the user data to a non-existent (exclusion method) or different analytics property and label it as internal traffic.
This non-IP methodology is easy to set up, and without further I do, let’s dive into the meat of this content.
One key thing to note is that the methodology explained in this article should work perfectly fine for all websites. However, you can build upon this strategy.
Here Is How You Setup Internal Traffic Filtering/Tracking In Google Tag Manager
We’ll start by creating our implementation design, and we’ll do this by answering key measurement questions regarding how we intend to identify internal traffic.
How Do We Identify Internal Traffic?
If you use GTM as your TMS, here are some of the generic ways you should use to identify internal traffic.
- If the traffic is from GTM preview mode
- If the URL has the following URL query string «?visitor_type=internal» (https://abc.com/?visitor_type=internal, more details on this)
💡The two method above is enough and should work perfectly fine for all websites.
Other non-generic methods are;
- If you own a WordPress CMS website, internal traffic visits the website by previewing the web page designs from the backend in either Elementor or standard page/post preview mode, with the query string «?preview=true» present in the URL.
- If you use Piwik Pro tag manager when previewing the website, the query string «?_stg_debug» will help you identify internal traffic.
- If you have the same GTM container on your staging website, which isn’t the best practice, then users visiting your staging domain are team members (I discussed this later in the article).
However, I won’t be diving into these methods.
To summarize everything about internal traffic identification;
- If you visit your website through the GTM preview mode (Google Tag Assistant), it should count as «internal traffic».
- Visitors to your site with the visitor_type query key as internal (https://abc.com/?visitor_type=internal) should count as internal traffic in GTM.
The next step will be how we set up these rules in Google Tag Manager.
Setting Up The Rules In GTM
1. The Debug Mode Rule
The first rule we’ll be setting up is to check if the user is viewing the website from Google tag assistant (the debug mode).
To do this, navigate to variables, click Configure under Built-In Variables and select the «Debug Mode» variable.
This variable returns true if you’re viewing the webpage from the Google Tag Assistant preview mode and false if it’s not.
2. The Generic Internal Traffic Rule
This GTM variable is essential for this tracking, which helps to identify the traffic of your team members who visit the website outside the GTM preview mode (this is where measurement culture comes into place).
You’ll have to ask your team members to always append this query string ?visitor_type=internal to the website URL, but they’ll not do this every time, just once in 3 months (you can change the period).
An easy way to do this is to ask your developer to set up a vanity URL («https://example.com/internal» is the vanity URL that gets redirected to «https://example.com/?visitor_type=internal«, and to be extra cautious, you can have a slack notification that notifies your team member to visit the URL every new or last month)
To create this variable, you’ll follow these steps;
- Create a new user-defined variable with URL as the type.
- Set your component type as «Query«.
- Add «visitor_type» as your Query Key.
- Expand «Format Value» and do the following;
- Convert to lowercase
- Convert null to external
- Convert undefined to external
The variable name will be «URL – Query – visitor_type«.
2.a Creating The Generic Internal Traffic Trigger
The first trigger you’ll create is for visitors visiting with the visitor_type query string set to internal. The following steps should make creating this trigger easy;
- Create a new trigger with Consent Initialization as your trigger type.
- Set the trigger to fire when the visitor_type variable («URL – Query – visitor_type») equals internal.
- The trigger name can be «CI – visitor_type Available».
After creating this trigger, we’ll have to attach it to a tag which we’ll be using to ensure that subsequent page visits and sessions in the next three (3) months don’t need to include the URL query string «?visitor_type=internal».
What does this mean?
It means if today, you visit your website example.com with this query string «?visitor_type=internal» (https://example.com/?visitor_type=internal), for subsequent page views and sessions for the next three (3) months, you don’t have to add that visitor_type query string again.
Automatically you’ll be tagged internal traffic anytime you visit the website using the same browser.
To make it easier for your team, you can ask your developer to set up a vanity URL https://example.com/internal, which will be redirected to https://example.com/?visitor_type=internal, making it easy and seamless for your internal team.
But how will you accomplish this?
The solution is cookies.
We’ll use a cookie for internal traffic identification for subsequent non-GTM preview mode team members’ visits to the site.
Here is the JavaScript code you should use to set the cookie with the name «visitor_type» in the user browser.
<script>
var cookieName = "visitor_type";
var cookieExpiry = new Date();
// Set expiry time of 90 days (in milliseconds)
cookieExpiry.setTime(cookieExpiry.getTime() + 90 * 24 * 60 * 60 * 1000);
var expires = "expires=" + cookieExpiry.toUTCString();
// Set cookie
document.cookie = cookieName + "=" + "internal" + ";" + expires + ";path=/;domain=." + location.hostname.replace(/^www\./i, "");
</script>
For this, we’ll create a new custom HTML tag, the name of the tag is «cHTML – Internal Traffic 90 Days Cookie».
The trigger that will be attached to this tag is the «CI – visitor_type Available» (which fires when the vistor_type query key equals «internal»).
Few things you need to know about this Javascript code;
- It expires in 90 days.
- Every time the JavaScript gets fired, it resets the cookie expiry period to a new 90 days period.
- The cookie’s name is «visitor_type».
- The cookie value is «internal», and this is because it’s only triggered when the traffic is internal (when «?visitor_type=internal» is present in the URL).
- You can change the period to whatever you like by changing «90» to your preferred number of days.
The next step of this implementation will be creating a first-party cookie variable used to retrieve and transform the cookie value of the «visitor_type» cookie.
These steps should guide you in creating this variable;
- Create a new user-defined variable with 1st Party Cookie as the type.
- Add the cookie name as «visitor_type«.
- Expand «Format Value» and do the following;
- Convert null to external
- Convert undefined to external
The variable name will be «1PC – visitor_type«.
After creating this variable, you’ll proceed to set up the last variable used to determine the traffic type.
Creating The Alpha Traffic Categorization Variable;
I call this the alpha variable of this implementation because this is where we’ll consolidate all internal traffic identification rules to determine if the user visiting the website is internal or external traffic.
It’s the brainbox of this implementation and will be used to determine if the website visitor is internal or external traffic.
This variable will be a Custom JavaScript variable type, and here is the code we’ll be using;
function() {
var typeByURL = '{{URL - Query - visitor_type}}';
var typeBy3MonthsCookie = '{{1PC - visitor_type}}';
var typeByDebugMode = {{Debug Mode}};
if (typeByURL == 'external' && typeBy3MonthsCookie == 'external' && typeByDebugMode === false) {
return "external";
}
else {
return "internal";
}
}
🆘 If you use the same GTM container for your live and staging domain, skip this code and use the next one.
But what does this code do?
It checks for three things;
- If the vistor_type query is external
- Is the 1st party cookie also external?
- And if the debug mode equals false (visits from outside GTM preview mode)
If all condition checks, it returns external as the traffic type. and if just one of these three (3) factors fails, then it’s internal traffic.
For example, if the visitor_type cookie is internal, the debug mode is false, and the vistor_type query is external, the user will be labelled internal traffic because one of the conditions for categorizing the traffic as external failed.
The variable name can be «CJS – User Traffic Type».
In scenarios where the same GTM container runs on the live and staging domain, use the code below instead.
function() {
var typeByURL = '{{URL - Query - visitor_type}}';
var typeBy3MonthsCookie = '{{1PC - visitor_type}}';
var typeByDebugMode = {{Debug Mode}};
var trackingDomain = '{{Page Hostname}}';
if (typeByURL == 'external' && typeBy3MonthsCookie == 'external' && typeByDebugMode === false && trackingDomain != 'staging.com') {
return "external";
}
else {
return "internal";
}
}
Note: you’ll have to change the stagingdomain.com to your staging domain.
An extra configuration to be added to this variable is having undefined converted to external.
Hurray, now you’ve completed the traffic categorization rule. Next on the list is debugging and testing.
Testing Your Instrumentation
You can use GTM preview mode to debug this, but my best shot will be using dataLayer in a custom HTML tag to test this.
How will you do this?
The first step will be creating a custom HTML tag, where you’ll copy and paste the code below.
You can name the tag «z_cHTML DataLayer Test (Delete)» because you’ll later have to delete it.
Ensure that the «user_traffic» key in the dataLayer uses the correct variable («CJS – User Traffic Type», the alpha variable).
Add the All Pages trigger, save, and boom!! You should now test your implementation.
Now test for the following internal traffic scenarios;
- First, visit your website through the GTM preview mode.
- Visit with the visitor_type query string in the URL (https://example.com/?visitor_type=internal, do it outside GTM preview mode).
- Visit subsequent pages without the query string.
- After some hours from ending your session, in the same browser, start a new session without using the visitor_type query and the GTM preview mode.
For all these scenarios, In the dataLayer, the value of the key «user_traffic» will be internal.
The next question might be how to filter this out (exclusion method) or label them in our analytics (we’ll be using GA4 here), but it’s pretty much the same for other measurement tools.
The Exclusion Method:
This approach is best for you if your goal is not to have internal traffic data sent to your production analytics stack.
You’ll create a lookup variable in Google Tag Manager, the input for this variable will be the alpha traffic identification variable (CJS – User Traffic Type).
Add two input fields;
- The «external» input will have in its output field the correct measurement ID, which is the production GA4 measurement ID.
- The «Internal» input field will have its output field use a non-existence measurement ID or probably a staging GA4 property.
- For the Default Value, let it be the live GA4 measurement ID.
This variable («LT – GA4 Measurement ID – Based on Traffic Type«) is what you’ll add to your GA4 configuration tag.
Follow the same approach for your Hotjar, Lucky Orange, Fullstory and other measurement stacks.
Create a lookup table variable where you’ll control the tracking ID based on the traffic type.
The beautiful thing about this approach is its usability across analytics implementation and conversion tracking.
For example, you can exclude internal tracking in your Facebook pixel, LinkedIn insight conversion tag, Google Ads conversion, and other conversion pixels.
The Inclusion + Labelling Method:
This approach fits scenarios where you’d be sending internal and external traffic to the same analytics property.
To do this, you use an event parameter or custom dimension for tools like Piwik Pro to label the hit based on the traffic type.
For GA4, all you’ll have to do is;
- Add a parameter «traffic_type» to the config tag.
- Let the value for the traffic_type field be the alpha traffic categorization variable («CJS – User Traffic Type«).
- Make the Internal Traffic filter active (you’ll find this under data settings in the admin section of your GA4 property).
While for other analytics tools, you might not need to do anything extra in the product interface.
Challenges Of Using The Non-IP Approach;
Non-IP methodology of tracking/filtering your team visits to your website has its own challenges.
For example, if you own multiple browser accounts, your first visit in all these browsers needs to include the visitor_type query in the website URL, but not for subsequent page views and website visits in the next 90 days unless the cookie expires or gets deleted.
Other challenges are;
- Not having a well-communicated measurement culture; where teammates know they are to visit the website using the vanity URL once per week (it should redirect to the website URL with the visitor_type query key)
- In a scenario where cookies are cleared or get deleted from the user’s browser, it can affect your tracking (which is why weekly URL visits will be helpful).
- Users of Chrome browsers who don’t have their browser synced will cause the internal identification cookie not to be available across the user devices.
Conclusion:
In this article, we looked at how analytics platform filter traffic using IPs, the challenges with this approach, how the non-IP methodology works, and how to implement it in Google Tag Manager.
First, we talked about how to identify internal traffic and how to set up the following variables;
- GTM debug mode
- Variable for the visitor_type query key
Next, we created the trigger for firing the tag that helps set the visitor_type cookie on the user’s browser for three months.
Remember, you can change the cookie expiration period from this line of the code.
cookieExpiry.setTime(cookieExpiry.getTime() + 90 * 24 * 60 * 60 * 1000
In this guide, we created the visitor_type first-party cookie and the alpha variable, which checks different internal identification rules before categorizing the user visits as internal or external.
We also tested the GTM setup, using both the dataLayer and the GTM preview approach (the dataLayer approach helps to check things outside Google Tag Assistant preview mode).
In the end, we discussed how to filter out your team’s website visits or include them but have them labelled in your analytics stack, using Google Analytics 4 as the example, which is the same for other measurement stacks.
In this guide, we also looked at the challenges this methodology could face, but overall, I recommend this strategy over IP dependent approach.
Let me know what you think in the comment below.
You are the fucking best. I love you. The internet was invented so you could write this guide