Complete GTM Solution for Internal Traffic Self-Identification

Use this GTM solution in cases where it is difficult—yet essential—to keep internal traffic out of your reporting

by Plamen Arnaudov 

Solution Outline

The steps below detail how to provide both desktop and mobile browser users with a quick and easy way to self-identify as internal traffic using Google Tag Manager (GTM). Any subsequent activities from their browser will be muted completely until they clear all their cookies.

After thinking long and hard, we decided that the self-identification approach (which can be easily combined with other methods) is the most flexible and universal one. While it does rely on end user cooperation, it has the added benefit of enabling filtering across a wide range of devices that users may hop on and off of. It's relatively easy to roll out, and it's the only approach that users on private mobile devices are likely to be able to apply and re-apply quickly.

By making self-identification user-friendly—just press and hold for 3 seconds along the top edge of any site page—we're hoping that word of mouth in the organization is sufficient to reach a healthy percentage of remote users.

The solution has the added benefit of placing no burden on IT, leaving resources free to work on deploying other approaches that are more baked into devices that the organization has control over.


Implementation Steps:

1. Create a GTM variable based on a Data Layer var name. In this example, both vars are named "internal":


2. Create a trigger that we can later use to block any tags set to fire at "Page View - DOM Ready":


3. Create a Custom HTML tag set to fire on all pages, as early as possible, at "All Pages - Page View":


4. Copy-paste the code below into the HTML field of the custom tag: 

(function() {

    var storageKeyName = '_internal';
    var varName = 'internal';
    var msg = "OK, Internal.";

    var dataLayer = window.dataLayer;
    var pressHoldDuration = 3 * 1000;
    var el = document;
    var timer;
    el.addEventListener("mousedown", pressing, false);
    el.addEventListener("mouseup", notPressing, false);
    el.addEventListener("touchstart", pressing, false);
    el.addEventListener("touchend", notPressing, false);
    function pressing(e) {
      var y = e.touches ? e.touches[0].clientY : e.clientY;
      if (y > 30)
      timer = setTimeout(setInternal, pressHoldDuration);
    function notPressing(e) {
      //console.log("Not pressing!");
    function setInternal(e) {
      !window.localStorage || window.localStorage.setItem(storageKeyName, true);
      //console.log("localStorage key set:", storageKeyName);
      var node = document.createElement("div"); = 'fixed'; = = = "10px"; = 'rgba(0, 0, 0, 0.1)'; = 999999; = 'rgba(255, 255, 255, 0.7)';
      var text = document.createTextNode(msg);
      setTimeout(function() { document.body.removeChild(node); }, pressHoldDuration);
    if (window.localStorage && window.localStorage.getItem(storageKeyName)) {
        var data = {}; data[varName] = true;
     	!dataLayer || dataLayer.push(data); 
        //console.log("localStorage key was found and placed in dataLayer:", varName);




5. Use the trigger you configured at step 2 to block any tags set to fire at "DOM Ready".

If you need to block tags at "Window Loaded" or at some custom event, you will need a separate blocking trigger, or a modification to your existing firing trigger.

In the example below, we are using the blocking trigger to cut off the Firebase App + Webb tracking completely for any users self-identifying as "Internal":


6. Test your implementation:
  • Pressing and holding the mouse (or finger) for 3 sec (configurable at step 4) along the top edge of any page should trigger the following message:

  • From that moment on, you should be seeing a message entering your dataLayer soon after "Page View" that sets "internal" to true for your browser. This message will normally persist until this browser's cookies are cleared:

  • If at any point you wish to reset your Internal status, the easiest way is by deleting the flag in F12 > Application > Local Storage. You may want to clear the flag to confirm that browsers without "_internal" (name configurable at step 4) have no dataLayer message and will still fire all tracking:


Advanced Tips:

  • GTM managers with a need to block tags fired as early as "Page View" may wish configure a custom variable that doesn't rely on the dataLayer message and instead reads the _internal storage key directly:

function() {

   return window.localStorage ? window.localStorage.getItem('_internal') : false;


  • Those of you who are conversant in JavaScript will notice that the solution can be easily adapted to fire only when a certain page element is pressed and held. You just need to point the var el to the right element and remove the 30-pixel boundary check in the function pressing. Obviously, this element either has to be available very early in the page load, or else be created by the code itself:


    var el = document.getElementById('#myelid');
    function pressing(e) {
      //var y = e.touches ? e.touches[0].clientY : e.clientY;
      //if (y > 30)


 About QA2L

QA2L is a data governance platform specializing in the automated validation of tracking tags/pixels. We focus on making it easy to automate even the most complicated user journeys / flows and to QA all your KPIs in a robust set of tests that is a breeze to maintain.

We take a smart, targeted approach to issue discovery via auto-selective site audits and scans and can help your organization on the path of improved data governance and data quality.

Contact Us


Tags: Data Quality Google Analytics Tips

Subscribe to our quarterly data quality newsletter